diff --git a/backend/local/counthookaction_string.go b/backend/local/counthookaction_string.go
index 92b2624a5..574a8c6cb 100644
--- a/backend/local/counthookaction_string.go
+++ b/backend/local/counthookaction_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT.
+// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT
package local
diff --git a/backend/operationtype_string.go b/backend/operationtype_string.go
index 15fbba6ec..6edadb919 100644
--- a/backend/operationtype_string.go
+++ b/backend/operationtype_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT.
+// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT
package backend
diff --git a/builtin/providers/oneandone/config.go b/builtin/providers/oneandone/config.go
new file mode 100644
index 000000000..1192c84e7
--- /dev/null
+++ b/builtin/providers/oneandone/config.go
@@ -0,0 +1,24 @@
+package oneandone
+
+import (
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+)
+
+type Config struct {
+ Token string
+ Retries int
+ Endpoint string
+ API *oneandone.API
+}
+
+func (c *Config) Client() (*Config, error) {
+ token := oneandone.SetToken(c.Token)
+
+ if len(c.Endpoint) > 0 {
+ c.API = oneandone.New(token, c.Endpoint)
+ } else {
+ c.API = oneandone.New(token, oneandone.BaseUrl)
+ }
+
+ return c, nil
+}
diff --git a/builtin/providers/oneandone/provider.go b/builtin/providers/oneandone/provider.go
new file mode 100644
index 000000000..8cc65f19b
--- /dev/null
+++ b/builtin/providers/oneandone/provider.go
@@ -0,0 +1,56 @@
+package oneandone
+
+import (
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/schema"
+ "github.com/hashicorp/terraform/terraform"
+)
+
+func Provider() terraform.ResourceProvider {
+ return &schema.Provider{
+ Schema: map[string]*schema.Schema{
+ "token": {
+ Type: schema.TypeString,
+ Required: true,
+ DefaultFunc: schema.EnvDefaultFunc("ONEANDONE_TOKEN", nil),
+ Description: "1&1 token for API operations.",
+ },
+ "retries": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Default: 50,
+ DefaultFunc: schema.EnvDefaultFunc("ONEANDONE_RETRIES", nil),
+ },
+ "endpoint": {
+ Type: schema.TypeString,
+ Optional: true,
+ Default: oneandone.BaseUrl,
+ DefaultFunc: schema.EnvDefaultFunc("ONEANDONE_ENDPOINT", nil),
+ },
+ },
+ ResourcesMap: map[string]*schema.Resource{
+ "oneandone_server": resourceOneandOneServer(),
+ "oneandone_firewall_policy": resourceOneandOneFirewallPolicy(),
+ "oneandone_private_network": resourceOneandOnePrivateNetwork(),
+ "oneandone_public_ip": resourceOneandOnePublicIp(),
+ "oneandone_shared_storage": resourceOneandOneSharedStorage(),
+ "oneandone_monitoring_policy": resourceOneandOneMonitoringPolicy(),
+ "oneandone_loadbalancer": resourceOneandOneLoadbalancer(),
+ "oneandone_vpn": resourceOneandOneVPN(),
+ },
+ ConfigureFunc: providerConfigure,
+ }
+}
+
+func providerConfigure(d *schema.ResourceData) (interface{}, error) {
+ var endpoint string
+ if d.Get("endpoint").(string) != oneandone.BaseUrl {
+ endpoint = d.Get("endpoint").(string)
+ }
+ config := Config{
+ Token: d.Get("token").(string),
+ Retries: d.Get("retries").(int),
+ Endpoint: endpoint,
+ }
+ return config.Client()
+}
diff --git a/builtin/providers/oneandone/provider_test.go b/builtin/providers/oneandone/provider_test.go
new file mode 100644
index 000000000..2057aac6d
--- /dev/null
+++ b/builtin/providers/oneandone/provider_test.go
@@ -0,0 +1,36 @@
+package oneandone
+
+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{
+ "oneandone": testAccProvider,
+ }
+}
+
+func TestProvider(t *testing.T) {
+ if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
+ t.Fatalf("err: %s", err)
+ }
+}
+
+func TestProvider_impl(t *testing.T) {
+ var _ terraform.ResourceProvider = Provider()
+}
+
+func testAccPreCheck(t *testing.T) {
+ if v := os.Getenv("ONEANDONE_TOKEN"); v == "" {
+ t.Fatal("ONEANDONE_TOKEN must be set for acceptance tests")
+ }
+}
diff --git a/builtin/providers/oneandone/resource_oneandone_firewall_policy.go b/builtin/providers/oneandone/resource_oneandone_firewall_policy.go
new file mode 100644
index 000000000..c62b63b5c
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_firewall_policy.go
@@ -0,0 +1,274 @@
+package oneandone
+
+import (
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/schema"
+ "github.com/hashicorp/terraform/helper/validation"
+ "strings"
+)
+
+func resourceOneandOneFirewallPolicy() *schema.Resource {
+ return &schema.Resource{
+
+ Create: resourceOneandOneFirewallCreate,
+ Read: resourceOneandOneFirewallRead,
+ Update: resourceOneandOneFirewallUpdate,
+ Delete: resourceOneandOneFirewallDelete,
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "rules": {
+ Type: schema.TypeList,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "protocol": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "port_from": {
+ Type: schema.TypeInt,
+ Optional: true,
+ ValidateFunc: validation.IntBetween(1, 65535),
+ },
+ "port_to": {
+ Type: schema.TypeInt,
+ Optional: true,
+ ValidateFunc: validation.IntBetween(1, 65535),
+ },
+ "source_ip": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ },
+ }
+}
+
+func resourceOneandOneFirewallCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ req := oneandone.FirewallPolicyRequest{
+ Name: d.Get("name").(string),
+ }
+
+ if desc, ok := d.GetOk("description"); ok {
+ req.Description = desc.(string)
+ }
+
+ req.Rules = getRules(d)
+
+ fw_id, fw, err := config.API.CreateFirewallPolicy(&req)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ d.SetId(fw_id)
+
+ if err != nil {
+ return err
+ }
+
+ return resourceOneandOneFirewallRead(d, meta)
+}
+
+func resourceOneandOneFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+ if d.HasChange("name") || d.HasChange("description") {
+ fw, err := config.API.UpdateFirewallPolicy(d.Id(), d.Get("name").(string), d.Get("description").(string))
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+
+ if d.HasChange("rules") {
+ oldR, newR := d.GetChange("rules")
+ oldValues := oldR.([]interface{})
+ newValues := newR.([]interface{})
+ if len(oldValues) > len(newValues) {
+ diff := difference(oldValues, newValues)
+ for _, old := range diff {
+ o := old.(map[string]interface{})
+ if o["id"] != nil {
+ old_id := o["id"].(string)
+ fw, err := config.API.DeleteFirewallPolicyRule(d.Id(), old_id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ } else {
+ var rules []oneandone.FirewallPolicyRule
+
+ for _, raw := range newValues {
+ rl := raw.(map[string]interface{})
+
+ if rl["id"].(string) == "" {
+ rule := oneandone.FirewallPolicyRule{
+ Protocol: rl["protocol"].(string),
+ }
+
+ if rl["port_from"] != nil {
+ rule.PortFrom = oneandone.Int2Pointer(rl["port_from"].(int))
+ }
+ if rl["port_to"] != nil {
+ rule.PortTo = oneandone.Int2Pointer(rl["port_to"].(int))
+ }
+
+ if rl["source_ip"] != nil {
+ rule.SourceIp = rl["source_ip"].(string)
+ }
+
+ rules = append(rules, rule)
+ }
+ }
+
+ if len(rules) > 0 {
+ fw, err := config.API.AddFirewallPolicyRules(d.Id(), rules)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
+ }
+ }
+ }
+
+ return resourceOneandOneFirewallRead(d, meta)
+}
+
+func resourceOneandOneFirewallRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ fw, err := config.API.GetFirewallPolicy(d.Id())
+ if err != nil {
+ if strings.Contains(err.Error(), "404") {
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ d.Set("rules", readRules(d, fw.Rules))
+ d.Set("description", fw.Description)
+
+ return nil
+}
+
+func resourceOneandOneFirewallDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ fp, err := config.API.DeleteFirewallPolicy(d.Id())
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitUntilDeleted(fp)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func readRules(d *schema.ResourceData, rules []oneandone.FirewallPolicyRule) interface{} {
+ rawRules := d.Get("rules").([]interface{})
+ counter := 0
+ for _, rR := range rawRules {
+ if len(rules) > counter {
+ rawMap := rR.(map[string]interface{})
+ rawMap["id"] = rules[counter].Id
+ if rules[counter].SourceIp != "0.0.0.0" {
+ rawMap["source_ip"] = rules[counter].SourceIp
+ }
+ }
+ counter++
+ }
+
+ return rawRules
+}
+
+func getRules(d *schema.ResourceData) []oneandone.FirewallPolicyRule {
+ var rules []oneandone.FirewallPolicyRule
+
+ if raw, ok := d.GetOk("rules"); ok {
+ rawRules := raw.([]interface{})
+
+ for _, raw := range rawRules {
+ rl := raw.(map[string]interface{})
+ rule := oneandone.FirewallPolicyRule{
+ Protocol: rl["protocol"].(string),
+ }
+
+ if rl["port_from"] != nil {
+ rule.PortFrom = oneandone.Int2Pointer(rl["port_from"].(int))
+ }
+ if rl["port_to"] != nil {
+ rule.PortTo = oneandone.Int2Pointer(rl["port_to"].(int))
+ }
+
+ if rl["source_ip"] != nil {
+ rule.SourceIp = rl["source_ip"].(string)
+ }
+
+ rules = append(rules, rule)
+ }
+ }
+ return rules
+}
+
+func difference(oldV, newV []interface{}) (toreturn []interface{}) {
+ var (
+ lenMin int
+ longest []interface{}
+ )
+ // Determine the shortest length and the longest slice
+ if len(oldV) < len(newV) {
+ lenMin = len(oldV)
+ longest = newV
+ } else {
+ lenMin = len(newV)
+ longest = oldV
+ }
+ // compare common indeces
+ for i := 0; i < lenMin; i++ {
+ if oldV[i] == nil || newV[i] == nil {
+ continue
+ }
+ if oldV[i].(map[string]interface{})["id"] != newV[i].(map[string]interface{})["id"] {
+ toreturn = append(toreturn, newV) //out += fmt.Sprintf("=>\t%s\t%s\n", oldV[i], newV[i])
+ }
+ }
+ // add indeces not in common
+ for _, v := range longest[lenMin:] {
+ //out += fmt.Sprintf("=>\t%s\n", v)
+ toreturn = append(toreturn, v)
+ }
+ return toreturn
+}
diff --git a/builtin/providers/oneandone/resource_oneandone_firewall_policy_test.go b/builtin/providers/oneandone/resource_oneandone_firewall_policy_test.go
new file mode 100644
index 000000000..146d63c3c
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_firewall_policy_test.go
@@ -0,0 +1,178 @@
+package oneandone
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ "os"
+ "time"
+)
+
+func TestAccOneandoneFirewall_Basic(t *testing.T) {
+ var firewall oneandone.FirewallPolicy
+
+ name := "test"
+ name_updated := "test1"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDOneandoneFirewallDestroyCheck,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneFirewall_basic, name),
+
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneFirewallExists("oneandone_firewall_policy.fw", &firewall),
+ testAccCheckOneandoneFirewallAttributes("oneandone_firewall_policy.fw", name),
+ resource.TestCheckResourceAttr("oneandone_firewall_policy.fw", "name", name),
+ ),
+ },
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneFirewall_update, name_updated),
+
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneFirewallExists("oneandone_firewall_policy.fw", &firewall),
+ testAccCheckOneandoneFirewallAttributes("oneandone_firewall_policy.fw", name_updated),
+ resource.TestCheckResourceAttr("oneandone_firewall_policy.fw", "name", name_updated),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckDOneandoneFirewallDestroyCheck(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "oneandone_firewall_policy.fw" {
+ continue
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ _, err := api.GetFirewallPolicy(rs.Primary.ID)
+
+ if err == nil {
+ return fmt.Errorf("Firewall Policy still exists %s %s", rs.Primary.ID, err.Error())
+ }
+ }
+
+ return nil
+}
+func testAccCheckOneandoneFirewallAttributes(n string, reverse_dns string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+ if rs.Primary.Attributes["name"] != reverse_dns {
+ return fmt.Errorf("Bad name: expected %s : found %s ", reverse_dns, rs.Primary.Attributes["name"])
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckOneandoneFirewallExists(n string, fw_p *oneandone.FirewallPolicy) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No Record ID is set")
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ found_fw, err := api.GetFirewallPolicy(rs.Primary.ID)
+
+ if err != nil {
+ return fmt.Errorf("Error occured while fetching Firewall Policy: %s", rs.Primary.ID)
+ }
+ if found_fw.Id != rs.Primary.ID {
+ return fmt.Errorf("Record not found")
+ }
+ fw_p = found_fw
+
+ return nil
+ }
+}
+
+const testAccCheckOneandoneFirewall_basic = `
+resource "oneandone_firewall_policy" "fw" {
+ name = "%s"
+ rules = [
+ {
+ "protocol" = "TCP"
+ "port_from" = 80
+ "port_to" = 80
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "ICMP"
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "TCP"
+ "port_from" = 43
+ "port_to" = 43
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "TCP"
+ "port_from" = 22
+ "port_to" = 22
+ "source_ip" = "0.0.0.0"
+ }
+ ]
+}`
+
+const testAccCheckOneandoneFirewall_update = `
+resource "oneandone_firewall_policy" "fw" {
+ name = "%s"
+ rules = [
+ {
+ "protocol" = "TCP"
+ "port_from" = 80
+ "port_to" = 80
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "ICMP"
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "TCP"
+ "port_from" = 43
+ "port_to" = 43
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "TCP"
+ "port_from" = 22
+ "port_to" = 22
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "TCP"
+ "port_from" = 88
+ "port_to" = 88
+ "source_ip" = "0.0.0.0"
+ },
+ ]
+}`
diff --git a/builtin/providers/oneandone/resource_oneandone_loadbalancer.go b/builtin/providers/oneandone/resource_oneandone_loadbalancer.go
new file mode 100644
index 000000000..627ec51df
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_loadbalancer.go
@@ -0,0 +1,370 @@
+package oneandone
+
+import (
+ "fmt"
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/schema"
+ "github.com/hashicorp/terraform/helper/validation"
+ "log"
+ "strings"
+)
+
+func resourceOneandOneLoadbalancer() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceOneandOneLoadbalancerCreate,
+ Read: resourceOneandOneLoadbalancerRead,
+ Update: resourceOneandOneLoadbalancerUpdate,
+ Delete: resourceOneandOneLoadbalancerDelete,
+ Schema: map[string]*schema.Schema{
+
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "method": {
+ Type: schema.TypeString,
+ Required: true,
+ ValidateFunc: validateMethod,
+ },
+ "datacenter": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "persistence": {
+ Type: schema.TypeBool,
+ Optional: true,
+ },
+ "persistence_time": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "health_check_test": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "health_check_interval": {
+ Type: schema.TypeInt,
+ Optional: true,
+ },
+ "health_check_path": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "health_check_path_parser": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "rules": {
+ Type: schema.TypeList,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "protocol": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "port_balancer": {
+ Type: schema.TypeInt,
+ Required: true,
+ ValidateFunc: validation.IntBetween(1, 65535),
+ },
+ "port_server": {
+ Type: schema.TypeInt,
+ Required: true,
+ ValidateFunc: validation.IntBetween(1, 65535),
+ },
+ "source_ip": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ },
+ }
+}
+
+func resourceOneandOneLoadbalancerCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ req := oneandone.LoadBalancerRequest{
+ Name: d.Get("name").(string),
+ Rules: getLBRules(d),
+ }
+
+ if raw, ok := d.GetOk("description"); ok {
+ req.Description = raw.(string)
+ }
+
+ if raw, ok := d.GetOk("datacenter"); ok {
+ dcs, err := config.API.ListDatacenters()
+ if err != nil {
+ return fmt.Errorf("An error occured while fetching list of datacenters %s", err)
+ }
+
+ decenter := raw.(string)
+ for _, dc := range dcs {
+ if strings.ToLower(dc.CountryCode) == strings.ToLower(decenter) {
+ req.DatacenterId = dc.Id
+ break
+ }
+ }
+ }
+
+ if raw, ok := d.GetOk("method"); ok {
+ req.Method = raw.(string)
+ }
+
+ if raw, ok := d.GetOk("persistence"); ok {
+ req.Persistence = oneandone.Bool2Pointer(raw.(bool))
+ }
+ if raw, ok := d.GetOk("persistence_time"); ok {
+ req.PersistenceTime = oneandone.Int2Pointer(raw.(int))
+ }
+
+ if raw, ok := d.GetOk("health_check_test"); ok {
+ req.HealthCheckTest = raw.(string)
+ }
+ if raw, ok := d.GetOk("health_check_interval"); ok {
+ req.HealthCheckInterval = oneandone.Int2Pointer(raw.(int))
+ }
+ if raw, ok := d.GetOk("health_check_path"); ok {
+ req.HealthCheckPath = raw.(string)
+ }
+ if raw, ok := d.GetOk("health_check_path_parser"); ok {
+ req.HealthCheckPathParser = raw.(string)
+ }
+
+ lb_id, lb, err := config.API.CreateLoadBalancer(&req)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(lb, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ d.SetId(lb_id)
+
+ return resourceOneandOneLoadbalancerRead(d, meta)
+}
+
+func getLBRules(d *schema.ResourceData) []oneandone.LoadBalancerRule {
+ var rules []oneandone.LoadBalancerRule
+
+ if raw, ok := d.GetOk("rules"); ok {
+ rawRules := raw.([]interface{})
+ log.Println("[DEBUG] raw rules:", raw)
+ for _, raw := range rawRules {
+ rl := raw.(map[string]interface{})
+ rule := oneandone.LoadBalancerRule{
+ Protocol: rl["protocol"].(string),
+ }
+
+ if rl["port_balancer"] != nil {
+ rule.PortBalancer = uint16(rl["port_balancer"].(int))
+ }
+ if rl["port_server"] != nil {
+ rule.PortServer = uint16(rl["port_server"].(int))
+ }
+
+ if rl["source_ip"] != nil {
+ rule.Source = rl["source_ip"].(string)
+ }
+
+ rules = append(rules, rule)
+ }
+ }
+ return rules
+}
+
+func resourceOneandOneLoadbalancerUpdate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ if d.HasChange("name") || d.HasChange("description") || d.HasChange("method") || d.HasChange("persistence") || d.HasChange("persistence_time") || d.HasChange("health_check_test") || d.HasChange("health_check_interval") {
+ lb := oneandone.LoadBalancerRequest{}
+ if d.HasChange("name") {
+ _, n := d.GetChange("name")
+ lb.Name = n.(string)
+ }
+ if d.HasChange("description") {
+ _, n := d.GetChange("description")
+ lb.Description = n.(string)
+ }
+ if d.HasChange("method") {
+ _, n := d.GetChange("method")
+ lb.Method = (n.(string))
+ }
+ if d.HasChange("persistence") {
+ _, n := d.GetChange("persistence")
+ lb.Persistence = oneandone.Bool2Pointer(n.(bool))
+ }
+ if d.HasChange("persistence_time") {
+ _, n := d.GetChange("persistence_time")
+ lb.PersistenceTime = oneandone.Int2Pointer(n.(int))
+ }
+ if d.HasChange("health_check_test") {
+ _, n := d.GetChange("health_check_test")
+ lb.HealthCheckTest = n.(string)
+ }
+ if d.HasChange("health_check_path") {
+ _, n := d.GetChange("health_check_path")
+ lb.HealthCheckPath = n.(string)
+ }
+ if d.HasChange("health_check_path_parser") {
+ _, n := d.GetChange("health_check_path_parser")
+ lb.HealthCheckPathParser = n.(string)
+ }
+
+ ss, err := config.API.UpdateLoadBalancer(d.Id(), &lb)
+
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(ss, "ACTIVE", 10, 30)
+ if err != nil {
+ return err
+ }
+
+ }
+
+ if d.HasChange("rules") {
+ oldR, newR := d.GetChange("rules")
+ oldValues := oldR.([]interface{})
+ newValues := newR.([]interface{})
+ if len(oldValues) > len(newValues) {
+ diff := difference(oldValues, newValues)
+ for _, old := range diff {
+ o := old.(map[string]interface{})
+ if o["id"] != nil {
+ old_id := o["id"].(string)
+ fw, err := config.API.DeleteLoadBalancerRule(d.Id(), old_id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ } else {
+ var rules []oneandone.LoadBalancerRule
+ log.Println("[DEBUG] new values:", newValues)
+
+ for _, raw := range newValues {
+ rl := raw.(map[string]interface{})
+ log.Println("[DEBUG] rl:", rl)
+
+ if rl["id"].(string) == "" {
+ rule := oneandone.LoadBalancerRule{
+ Protocol: rl["protocol"].(string),
+ }
+
+ rule.PortServer = uint16(rl["port_server"].(int))
+ rule.PortBalancer = uint16(rl["port_balancer"].(int))
+
+ rule.Source = rl["source_ip"].(string)
+
+ log.Println("[DEBUG] adding to list", rl["protocol"], rl["source_ip"], rl["port_balancer"], rl["port_server"])
+ log.Println("[DEBUG] adding to list", rule)
+
+ rules = append(rules, rule)
+ }
+ }
+
+ log.Println("[DEBUG] new rules:", rules)
+
+ if len(rules) > 0 {
+ fw, err := config.API.AddLoadBalancerRules(d.Id(), rules)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
+ }
+ }
+ }
+
+ return resourceOneandOneLoadbalancerRead(d, meta)
+}
+
+func resourceOneandOneLoadbalancerRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ ss, err := config.API.GetLoadBalancer(d.Id())
+ if err != nil {
+ if strings.Contains(err.Error(), "404") {
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ d.Set("name", ss.Name)
+ d.Set("description", ss.Description)
+ d.Set("datacenter", ss.Datacenter.CountryCode)
+ d.Set("method", ss.Method)
+ d.Set("persistence", ss.Persistence)
+ d.Set("persistence_time", ss.PersistenceTime)
+ d.Set("health_check_test", ss.HealthCheckTest)
+ d.Set("health_check_interval", ss.HealthCheckInterval)
+ d.Set("rules", getLoadbalancerRules(ss.Rules))
+
+ return nil
+}
+
+func getLoadbalancerRules(rules []oneandone.LoadBalancerRule) []map[string]interface{} {
+ raw := make([]map[string]interface{}, 0, len(rules))
+
+ for _, rule := range rules {
+
+ toadd := map[string]interface{}{
+ "id": rule.Id,
+ "port_balancer": rule.PortBalancer,
+ "port_server": rule.PortServer,
+ "protocol": rule.Protocol,
+ "source_ip": rule.Source,
+ }
+
+ raw = append(raw, toadd)
+ }
+
+ return raw
+
+}
+
+func resourceOneandOneLoadbalancerDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ lb, err := config.API.DeleteLoadBalancer(d.Id())
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitUntilDeleted(lb)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func validateMethod(v interface{}, k string) (ws []string, errors []error) {
+ value := v.(string)
+
+ if value != "ROUND_ROBIN" && value != "LEAST_CONNECTIONS" {
+ errors = append(errors, fmt.Errorf("%q value sholud be either 'ROUND_ROBIN' or 'LEAST_CONNECTIONS' not %q", k, value))
+ }
+
+ return
+}
diff --git a/builtin/providers/oneandone/resource_oneandone_loadbalancer_test.go b/builtin/providers/oneandone/resource_oneandone_loadbalancer_test.go
new file mode 100644
index 000000000..ecd0f9443
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_loadbalancer_test.go
@@ -0,0 +1,156 @@
+package oneandone
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ "os"
+ "time"
+)
+
+func TestAccOneandoneLoadbalancer_Basic(t *testing.T) {
+ var lb oneandone.LoadBalancer
+
+ name := "test_loadbalancer"
+ name_updated := "test_loadbalancer_renamed"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDOneandoneLoadbalancerDestroyCheck,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneLoadbalancer_basic, name),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneLoadbalancerExists("oneandone_loadbalancer.lb", &lb),
+ testAccCheckOneandoneLoadbalancerAttributes("oneandone_loadbalancer.lb", name),
+ resource.TestCheckResourceAttr("oneandone_loadbalancer.lb", "name", name),
+ ),
+ },
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneLoadbalancer_update, name_updated),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneLoadbalancerExists("oneandone_loadbalancer.lb", &lb),
+ testAccCheckOneandoneLoadbalancerAttributes("oneandone_loadbalancer.lb", name_updated),
+ resource.TestCheckResourceAttr("oneandone_loadbalancer.lb", "name", name_updated),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckDOneandoneLoadbalancerDestroyCheck(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "oneandone_loadbalancer.lb" {
+ continue
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ _, err := api.GetLoadBalancer(rs.Primary.ID)
+
+ if err == nil {
+ return fmt.Errorf("Loadbalancer still exists %s %s", rs.Primary.ID, err.Error())
+ }
+ }
+
+ return nil
+}
+func testAccCheckOneandoneLoadbalancerAttributes(n string, reverse_dns string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+ if rs.Primary.Attributes["name"] != reverse_dns {
+ return fmt.Errorf("Bad name: expected %s : found %s ", reverse_dns, rs.Primary.Attributes["name"])
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckOneandoneLoadbalancerExists(n string, fw_p *oneandone.LoadBalancer) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No Record ID is set")
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ found_fw, err := api.GetLoadBalancer(rs.Primary.ID)
+
+ if err != nil {
+ return fmt.Errorf("Error occured while fetching Loadbalancer: %s", rs.Primary.ID)
+ }
+ if found_fw.Id != rs.Primary.ID {
+ return fmt.Errorf("Record not found")
+ }
+ fw_p = found_fw
+
+ return nil
+ }
+}
+
+const testAccCheckOneandoneLoadbalancer_basic = `
+resource "oneandone_loadbalancer" "lb" {
+ name = "%s"
+ method = "ROUND_ROBIN"
+ persistence = true
+ persistence_time = 60
+ health_check_test = "TCP"
+ health_check_interval = 300
+ datacenter = "US"
+ rules = [
+ {
+ protocol = "TCP"
+ port_balancer = 8080
+ port_server = 8089
+ source_ip = "0.0.0.0"
+ },
+ {
+ protocol = "TCP"
+ port_balancer = 9090
+ port_server = 9099
+ source_ip = "0.0.0.0"
+ }
+ ]
+}`
+
+const testAccCheckOneandoneLoadbalancer_update = `
+resource "oneandone_loadbalancer" "lb" {
+ name = "%s"
+ method = "ROUND_ROBIN"
+ persistence = true
+ persistence_time = 60
+ health_check_test = "TCP"
+ health_check_interval = 300
+ datacenter = "US"
+ rules = [
+ {
+ protocol = "TCP"
+ port_balancer = 8080
+ port_server = 8089
+ source_ip = "0.0.0.0"
+ }
+ ]
+}`
diff --git a/builtin/providers/oneandone/resource_oneandone_monitoring_policy.go b/builtin/providers/oneandone/resource_oneandone_monitoring_policy.go
new file mode 100644
index 000000000..a6af20dfc
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_monitoring_policy.go
@@ -0,0 +1,706 @@
+package oneandone
+
+import (
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/schema"
+ "strings"
+)
+
+func resourceOneandOneMonitoringPolicy() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceOneandOneMonitoringPolicyCreate,
+ Read: resourceOneandOneMonitoringPolicyRead,
+ Update: resourceOneandOneMonitoringPolicyUpdate,
+ Delete: resourceOneandOneMonitoringPolicyDelete,
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "email": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "agent": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ "thresholds": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "cpu": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "warning": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "critical": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "ram": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "warning": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "critical": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "disk": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "warning": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "critical": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "transfer": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "warning": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "critical": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "internal_ping": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "warning": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "critical": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "value": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "alert": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "ports": {
+ Type: schema.TypeList,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "email_notification": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ "port": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "protocol": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "alert_if": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ },
+ Optional: true,
+ },
+ "processes": {
+ Type: schema.TypeList,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+
+ "email_notification": {
+ Type: schema.TypeBool,
+ Required: true,
+ },
+ "process": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "alert_if": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ },
+ Optional: true,
+ },
+ },
+ }
+}
+
+func resourceOneandOneMonitoringPolicyCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ mp_request := oneandone.MonitoringPolicy{
+ Name: d.Get("name").(string),
+ Agent: d.Get("agent").(bool),
+ Thresholds: getThresholds(d.Get("thresholds")),
+ }
+
+ if raw, ok := d.GetOk("ports"); ok {
+ mp_request.Ports = getPorts(raw)
+ }
+
+ if raw, ok := d.GetOk("processes"); ok {
+ mp_request.Processes = getProcesses(raw)
+ }
+
+ mp_id, mp, err := config.API.CreateMonitoringPolicy(&mp_request)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ d.SetId(mp_id)
+
+ return resourceOneandOneMonitoringPolicyRead(d, meta)
+}
+
+func resourceOneandOneMonitoringPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ req := oneandone.MonitoringPolicy{}
+ if d.HasChange("name") {
+ _, n := d.GetChange("name")
+ req.Name = n.(string)
+ }
+
+ if d.HasChange("description") {
+ _, n := d.GetChange("description")
+ req.Description = n.(string)
+ }
+
+ if d.HasChange("email") {
+ _, n := d.GetChange("email")
+ req.Email = n.(string)
+ }
+
+ if d.HasChange("agent") {
+ _, n := d.GetChange("agent")
+ req.Agent = n.(bool)
+ }
+
+ if d.HasChange("thresholds") {
+ _, n := d.GetChange("thresholds")
+ req.Thresholds = getThresholds(n)
+ }
+
+ mp, err := config.API.UpdateMonitoringPolicy(d.Id(), &req)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ if d.HasChange("ports") {
+ o, n := d.GetChange("ports")
+ oldValues := o.([]interface{})
+ newValues := n.([]interface{})
+
+ if len(newValues) > len(oldValues) {
+ ports := getPorts(newValues)
+
+ newports := []oneandone.MonitoringPort{}
+
+ for _, p := range ports {
+ if p.Id == "" {
+ newports = append(newports, p)
+ }
+ }
+
+ mp, err := config.API.AddMonitoringPolicyPorts(d.Id(), newports)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ } else if len(oldValues) > len(newValues) {
+ diff := difference(oldValues, newValues)
+ ports := getPorts(diff)
+
+ for _, port := range ports {
+ if port.Id == "" {
+ continue
+ }
+
+ mp, err := config.API.DeleteMonitoringPolicyPort(d.Id(), port.Id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ } else if len(oldValues) == len(newValues) {
+ ports := getPorts(newValues)
+
+ for _, port := range ports {
+ mp, err := config.API.ModifyMonitoringPolicyPort(d.Id(), port.Id, &port)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+
+ if d.HasChange("processes") {
+ o, n := d.GetChange("processes")
+ oldValues := o.([]interface{})
+ newValues := n.([]interface{})
+ if len(newValues) > len(oldValues) {
+ processes := getProcesses(newValues)
+
+ newprocesses := []oneandone.MonitoringProcess{}
+
+ for _, p := range processes {
+ if p.Id == "" {
+ newprocesses = append(newprocesses, p)
+ }
+ }
+
+ mp, err := config.API.AddMonitoringPolicyProcesses(d.Id(), newprocesses)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ } else if len(oldValues) > len(newValues) {
+ diff := difference(oldValues, newValues)
+ processes := getProcesses(diff)
+ for _, process := range processes {
+ if process.Id == "" {
+ continue
+ }
+
+ mp, err := config.API.DeleteMonitoringPolicyProcess(d.Id(), process.Id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ } else if len(oldValues) == len(newValues) {
+ processes := getProcesses(newValues)
+
+ for _, process := range processes {
+ mp, err := config.API.ModifyMonitoringPolicyProcess(d.Id(), process.Id, &process)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+
+ return resourceOneandOneMonitoringPolicyRead(d, meta)
+}
+
+func resourceOneandOneMonitoringPolicyRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ mp, err := config.API.GetMonitoringPolicy(d.Id())
+ if err != nil {
+ if strings.Contains(err.Error(), "404") {
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ if len(mp.Servers) > 0 {
+ }
+
+ if len(mp.Ports) > 0 {
+ pports := d.Get("ports").([]interface{})
+ for i, raw_ports := range pports {
+ port := raw_ports.(map[string]interface{})
+ port["id"] = mp.Ports[i].Id
+ }
+ d.Set("ports", pports)
+ }
+
+ if len(mp.Processes) > 0 {
+ pprocesses := d.Get("processes").([]interface{})
+ for i, raw_processes := range pprocesses {
+ process := raw_processes.(map[string]interface{})
+ process["id"] = mp.Processes[i].Id
+ }
+ d.Set("processes", pprocesses)
+ }
+
+ return nil
+}
+
+func resourceOneandOneMonitoringPolicyDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ mp, err := config.API.DeleteMonitoringPolicy(d.Id())
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitUntilDeleted(mp)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func getThresholds(d interface{}) *oneandone.MonitoringThreshold {
+ raw_thresholds := d.(*schema.Set).List()
+
+ toReturn := &oneandone.MonitoringThreshold{}
+
+ for _, thresholds := range raw_thresholds {
+ th_set := thresholds.(map[string]interface{})
+
+ //CPU
+ cpu_raw := th_set["cpu"].(*schema.Set)
+ toReturn.Cpu = &oneandone.MonitoringLevel{}
+ for _, c := range cpu_raw.List() {
+ int_k := c.(map[string]interface{})
+ for _, w := range int_k["warning"].(*schema.Set).List() {
+ toReturn.Cpu.Warning = &oneandone.MonitoringValue{
+ Value: w.(map[string]interface{})["value"].(int),
+ Alert: w.(map[string]interface{})["alert"].(bool),
+ }
+ }
+
+ for _, c := range int_k["critical"].(*schema.Set).List() {
+ toReturn.Cpu.Critical = &oneandone.MonitoringValue{
+ Value: c.(map[string]interface{})["value"].(int),
+ Alert: c.(map[string]interface{})["alert"].(bool),
+ }
+ }
+ }
+ //RAM
+ ram_raw := th_set["ram"].(*schema.Set)
+ toReturn.Ram = &oneandone.MonitoringLevel{}
+ for _, c := range ram_raw.List() {
+ int_k := c.(map[string]interface{})
+ for _, w := range int_k["warning"].(*schema.Set).List() {
+ toReturn.Ram.Warning = &oneandone.MonitoringValue{
+ Value: w.(map[string]interface{})["value"].(int),
+ Alert: w.(map[string]interface{})["alert"].(bool),
+ }
+ }
+
+ for _, c := range int_k["critical"].(*schema.Set).List() {
+ toReturn.Ram.Critical = &oneandone.MonitoringValue{
+ Value: c.(map[string]interface{})["value"].(int),
+ Alert: c.(map[string]interface{})["alert"].(bool),
+ }
+ }
+ }
+
+ //DISK
+ disk_raw := th_set["disk"].(*schema.Set)
+ toReturn.Disk = &oneandone.MonitoringLevel{}
+ for _, c := range disk_raw.List() {
+ int_k := c.(map[string]interface{})
+ for _, w := range int_k["warning"].(*schema.Set).List() {
+ toReturn.Disk.Warning = &oneandone.MonitoringValue{
+ Value: w.(map[string]interface{})["value"].(int),
+ Alert: w.(map[string]interface{})["alert"].(bool),
+ }
+ }
+
+ for _, c := range int_k["critical"].(*schema.Set).List() {
+ toReturn.Disk.Critical = &oneandone.MonitoringValue{
+ Value: c.(map[string]interface{})["value"].(int),
+ Alert: c.(map[string]interface{})["alert"].(bool),
+ }
+ }
+ }
+
+ //TRANSFER
+ transfer_raw := th_set["transfer"].(*schema.Set)
+ toReturn.Transfer = &oneandone.MonitoringLevel{}
+ for _, c := range transfer_raw.List() {
+ int_k := c.(map[string]interface{})
+ for _, w := range int_k["warning"].(*schema.Set).List() {
+ toReturn.Transfer.Warning = &oneandone.MonitoringValue{
+ Value: w.(map[string]interface{})["value"].(int),
+ Alert: w.(map[string]interface{})["alert"].(bool),
+ }
+ }
+
+ for _, c := range int_k["critical"].(*schema.Set).List() {
+ toReturn.Transfer.Critical = &oneandone.MonitoringValue{
+ Value: c.(map[string]interface{})["value"].(int),
+ Alert: c.(map[string]interface{})["alert"].(bool),
+ }
+ }
+ }
+ //internal ping
+ ping_raw := th_set["internal_ping"].(*schema.Set)
+ toReturn.InternalPing = &oneandone.MonitoringLevel{}
+ for _, c := range ping_raw.List() {
+ int_k := c.(map[string]interface{})
+ for _, w := range int_k["warning"].(*schema.Set).List() {
+ toReturn.InternalPing.Warning = &oneandone.MonitoringValue{
+ Value: w.(map[string]interface{})["value"].(int),
+ Alert: w.(map[string]interface{})["alert"].(bool),
+ }
+ }
+
+ for _, c := range int_k["critical"].(*schema.Set).List() {
+ toReturn.InternalPing.Critical = &oneandone.MonitoringValue{
+ Value: c.(map[string]interface{})["value"].(int),
+ Alert: c.(map[string]interface{})["alert"].(bool),
+ }
+ }
+ }
+ }
+
+ return toReturn
+}
+
+func getProcesses(d interface{}) []oneandone.MonitoringProcess {
+ toReturn := []oneandone.MonitoringProcess{}
+
+ for _, raw := range d.([]interface{}) {
+ port := raw.(map[string]interface{})
+ m_port := oneandone.MonitoringProcess{
+ EmailNotification: port["email_notification"].(bool),
+ }
+
+ if port["id"] != nil {
+ m_port.Id = port["id"].(string)
+ }
+
+ if port["process"] != nil {
+ m_port.Process = port["process"].(string)
+ }
+
+ if port["alert_if"] != nil {
+ m_port.AlertIf = port["alert_if"].(string)
+ }
+
+ toReturn = append(toReturn, m_port)
+ }
+
+ return toReturn
+}
+
+func getPorts(d interface{}) []oneandone.MonitoringPort {
+ toReturn := []oneandone.MonitoringPort{}
+
+ for _, raw := range d.([]interface{}) {
+ port := raw.(map[string]interface{})
+ m_port := oneandone.MonitoringPort{
+ EmailNotification: port["email_notification"].(bool),
+ Port: port["port"].(int),
+ }
+
+ if port["id"] != nil {
+ m_port.Id = port["id"].(string)
+ }
+
+ if port["protocol"] != nil {
+ m_port.Protocol = port["protocol"].(string)
+ }
+
+ if port["alert_if"] != nil {
+ m_port.AlertIf = port["alert_if"].(string)
+ }
+
+ toReturn = append(toReturn, m_port)
+ }
+
+ return toReturn
+}
diff --git a/builtin/providers/oneandone/resource_oneandone_monitoring_policy_test.go b/builtin/providers/oneandone/resource_oneandone_monitoring_policy_test.go
new file mode 100644
index 000000000..c6727ee21
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_monitoring_policy_test.go
@@ -0,0 +1,212 @@
+package oneandone
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ "os"
+ "time"
+)
+
+func TestAccOneandoneMonitoringPolicy_Basic(t *testing.T) {
+ var mp oneandone.MonitoringPolicy
+
+ name := "test"
+ name_updated := "test1"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDOneandoneMonitoringPolicyDestroyCheck,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneMonitoringPolicy_basic, name),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneMonitoringPolicyExists("oneandone_monitoring_policy.mp", &mp),
+ testAccCheckOneandoneMonitoringPolicyAttributes("oneandone_monitoring_policy.mp", name),
+ resource.TestCheckResourceAttr("oneandone_monitoring_policy.mp", "name", name),
+ ),
+ },
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneMonitoringPolicy_basic, name_updated),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneMonitoringPolicyExists("oneandone_monitoring_policy.mp", &mp),
+ testAccCheckOneandoneMonitoringPolicyAttributes("oneandone_monitoring_policy.mp", name_updated),
+ resource.TestCheckResourceAttr("oneandone_monitoring_policy.mp", "name", name_updated),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckDOneandoneMonitoringPolicyDestroyCheck(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "oneandone_monitoring_policy.mp" {
+ continue
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ _, err := api.GetMonitoringPolicy(rs.Primary.ID)
+
+ if err == nil {
+ return fmt.Errorf("MonitoringPolicy still exists %s %s", rs.Primary.ID, err.Error())
+ }
+ }
+
+ return nil
+}
+func testAccCheckOneandoneMonitoringPolicyAttributes(n string, reverse_dns string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+ if rs.Primary.Attributes["name"] != reverse_dns {
+ return fmt.Errorf("Bad name: expected %s : found %s ", reverse_dns, rs.Primary.Attributes["name"])
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckOneandoneMonitoringPolicyExists(n string, fw_p *oneandone.MonitoringPolicy) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No Record ID is set")
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ found_fw, err := api.GetMonitoringPolicy(rs.Primary.ID)
+
+ if err != nil {
+ return fmt.Errorf("Error occured while fetching MonitoringPolicy: %s", rs.Primary.ID)
+ }
+ if found_fw.Id != rs.Primary.ID {
+ return fmt.Errorf("Record not found")
+ }
+ fw_p = found_fw
+
+ return nil
+ }
+}
+
+const testAccCheckOneandoneMonitoringPolicy_basic = `
+resource "oneandone_monitoring_policy" "mp" {
+ name = "%s"
+ agent = true
+ email = "email@address.com"
+ thresholds = {
+ cpu = {
+ warning = {
+ value = 50,
+ alert = false
+ }
+ critical = {
+ value = 66,
+ alert = false
+ }
+ }
+ ram = {
+ warning = {
+ value = 70,
+ alert = true
+ }
+ critical = {
+ value = 80,
+ alert = true
+ }
+ },
+ ram = {
+ warning = {
+ value = 85,
+ alert = true
+ }
+ critical = {
+ value = 95,
+ alert = true
+ }
+ },
+ disk = {
+ warning = {
+ value = 84,
+ alert = true
+ }
+ critical = {
+ value = 94,
+ alert = true
+ }
+ },
+ transfer = {
+ warning = {
+ value = 1000,
+ alert = true
+ }
+ critical = {
+ value = 2000,
+ alert = true
+ }
+ },
+ internal_ping = {
+ warning = {
+ value = 3000,
+ alert = true
+ }
+ critical = {
+ value = 4000,
+ alert = true
+ }
+ }
+ }
+ ports = [
+ {
+ email_notification = true
+ port = 443
+ protocol = "TCP"
+ alert_if = "NOT_RESPONDING"
+ },
+ {
+ email_notification = false
+ port = 80
+ protocol = "TCP"
+ alert_if = "NOT_RESPONDING"
+ },
+ {
+ email_notification = true
+ port = 21
+ protocol = "TCP"
+ alert_if = "NOT_RESPONDING"
+ }
+ ]
+ processes = [
+ {
+ email_notification = false
+ process = "httpdeamon"
+ alert_if = "RUNNING"
+ },
+ {
+ process = "iexplorer",
+ alert_if = "NOT_RUNNING"
+ email_notification = true
+ }]
+}`
diff --git a/builtin/providers/oneandone/resource_oneandone_private_network.go b/builtin/providers/oneandone/resource_oneandone_private_network.go
new file mode 100644
index 000000000..f9a4fc9e3
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_private_network.go
@@ -0,0 +1,291 @@
+package oneandone
+
+import (
+ "fmt"
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/schema"
+ "strings"
+)
+
+func resourceOneandOnePrivateNetwork() *schema.Resource {
+ return &schema.Resource{
+
+ Create: resourceOneandOnePrivateNetworkCreate,
+ Read: resourceOneandOnePrivateNetworkRead,
+ Update: resourceOneandOnePrivateNetworkUpdate,
+ Delete: resourceOneandOnePrivateNetworkDelete,
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "datacenter": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "network_address": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "subnet_mask": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "server_ids": {
+ Type: schema.TypeSet,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Optional: true,
+ },
+ },
+ }
+}
+
+func resourceOneandOnePrivateNetworkCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ req := oneandone.PrivateNetworkRequest{
+ Name: d.Get("name").(string),
+ }
+
+ if raw, ok := d.GetOk("description"); ok {
+ req.Description = raw.(string)
+ }
+
+ if raw, ok := d.GetOk("network_address"); ok {
+ req.NetworkAddress = raw.(string)
+ }
+
+ if raw, ok := d.GetOk("subnet_mask"); ok {
+ req.SubnetMask = raw.(string)
+ }
+
+ if raw, ok := d.GetOk("datacenter"); ok {
+ dcs, err := config.API.ListDatacenters()
+
+ if err != nil {
+ return fmt.Errorf("An error occured while fetching list of datacenters %s", err)
+
+ }
+
+ decenter := raw.(string)
+ for _, dc := range dcs {
+ if strings.ToLower(dc.CountryCode) == strings.ToLower(decenter) {
+ req.DatacenterId = dc.Id
+ break
+ }
+ }
+ }
+
+ prn_id, prn, err := config.API.CreatePrivateNetwork(&req)
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(prn, "ACTIVE", 30, config.Retries)
+
+ if err != nil {
+ return err
+ }
+
+ d.SetId(prn_id)
+
+ var ids []string
+ if raw, ok := d.GetOk("server_ids"); ok {
+
+ rawIps := raw.(*schema.Set).List()
+
+ for _, raw := range rawIps {
+ ids = append(ids, raw.(string))
+ server, err := config.API.ShutdownServer(raw.(string), false)
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(server, "POWERED_OFF", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ }
+ }
+
+ prn, err = config.API.AttachPrivateNetworkServers(d.Id(), ids)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(prn, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ for _, id := range ids {
+ server, err := config.API.StartServer(id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(server, "POWERED_ON", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+
+ return resourceOneandOnePrivateNetworkRead(d, meta)
+}
+
+func resourceOneandOnePrivateNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+ if d.HasChange("name") || d.HasChange("description") || d.HasChange("network_address") || d.HasChange("subnet_mask") {
+ pnset := oneandone.PrivateNetworkRequest{}
+
+ pnset.Name = d.Get("name").(string)
+
+ pnset.Description = d.Get("description").(string)
+ pnset.NetworkAddress = d.Get("network_address").(string)
+ pnset.SubnetMask = d.Get("subnet_mask").(string)
+
+ prn, err := config.API.UpdatePrivateNetwork(d.Id(), &pnset)
+
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(prn, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+
+ if d.HasChange("server_ids") {
+ o, n := d.GetChange("server_ids")
+
+ newValues := n.(*schema.Set).List()
+ oldValues := o.(*schema.Set).List()
+
+ var ids []string
+ for _, newV := range oldValues {
+ ids = append(ids, newV.(string))
+ }
+ for _, id := range ids {
+ server, err := config.API.ShutdownServer(id, false)
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(server, "POWERED_OFF", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ _, err = config.API.RemoveServerPrivateNetwork(id, d.Id())
+ if err != nil {
+ return err
+ }
+
+ prn, _ := config.API.GetPrivateNetwork(d.Id())
+
+ err = config.API.WaitForState(prn, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ }
+
+ var newids []string
+
+ for _, newV := range newValues {
+ newids = append(newids, newV.(string))
+ }
+ pn, err := config.API.AttachPrivateNetworkServers(d.Id(), newids)
+
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(pn, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ for _, id := range newids {
+ server, err := config.API.StartServer(id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(server, "POWERED_ON", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return resourceOneandOnePrivateNetworkRead(d, meta)
+}
+
+func resourceOneandOnePrivateNetworkRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ pn, err := config.API.GetPrivateNetwork(d.Id())
+ if err != nil {
+ if strings.Contains(err.Error(), "404") {
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ d.Set("name", pn.Name)
+ d.Set("description", pn.Description)
+ d.Set("network_address", pn.NetworkAddress)
+ d.Set("subnet_mask", pn.SubnetMask)
+ d.Set("datacenter", pn.Datacenter.CountryCode)
+
+ var toAdd []string
+ for _, s := range pn.Servers {
+ toAdd = append(toAdd, s.Id)
+ }
+ d.Set("server_ids", toAdd)
+ return nil
+}
+
+func resourceOneandOnePrivateNetworkDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ pn, err := config.API.GetPrivateNetwork(d.Id())
+
+ for _, server := range pn.Servers {
+ srv, err := config.API.ShutdownServer(server.Id, false)
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(srv, "POWERED_OFF", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+
+ pn, err = config.API.DeletePrivateNetwork(d.Id())
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitUntilDeleted(pn)
+ if err != nil {
+ return err
+ }
+
+ for _, server := range pn.Servers {
+ srv, err := config.API.StartServer(server.Id)
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(srv, "POWERED_ON", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/builtin/providers/oneandone/resource_oneandone_private_network_test.go b/builtin/providers/oneandone/resource_oneandone_private_network_test.go
new file mode 100644
index 000000000..e91da76f2
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_private_network_test.go
@@ -0,0 +1,160 @@
+package oneandone
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ "os"
+ "time"
+)
+
+func TestAccOneandonePrivateNetwork_Basic(t *testing.T) {
+ var net oneandone.PrivateNetwork
+
+ name := "test"
+ name_updated := "test1"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckOneandonePrivateNetworkDestroyCheck,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandonePrivateNetwork_basic, name),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandonePrivateNetworkExists("oneandone_private_network.pn", &net),
+ testAccCheckOneandonePrivateNetworkAttributes("oneandone_private_network.pn", name),
+ resource.TestCheckResourceAttr("oneandone_private_network.pn", "name", name),
+ ),
+ },
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandonePrivateNetwork_basic, name_updated),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandonePrivateNetworkExists("oneandone_private_network.pn", &net),
+ testAccCheckOneandonePrivateNetworkAttributes("oneandone_private_network.pn", name_updated),
+ resource.TestCheckResourceAttr("oneandone_private_network.pn", "name", name_updated),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckOneandonePrivateNetworkDestroyCheck(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "oneandone_private_network" {
+ continue
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ _, err := api.GetPrivateNetwork(rs.Primary.ID)
+
+ if err == nil {
+ return fmt.Errorf("PrivateNetwork still exists %s %s", rs.Primary.ID, err.Error())
+ }
+ }
+
+ return nil
+}
+func testAccCheckOneandonePrivateNetworkAttributes(n string, reverse_dns string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+ if rs.Primary.Attributes["name"] != reverse_dns {
+ return fmt.Errorf("Bad name: expected %s : found %s ", reverse_dns, rs.Primary.Attributes["name"])
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckOneandonePrivateNetworkExists(n string, server *oneandone.PrivateNetwork) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No Record ID is set")
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ found_server, err := api.GetPrivateNetwork(rs.Primary.ID)
+
+ if err != nil {
+ return fmt.Errorf("Error occured while fetching PrivateNetwork: %s", rs.Primary.ID)
+ }
+ if found_server.Id != rs.Primary.ID {
+ return fmt.Errorf("Record not found")
+ }
+ server = found_server
+
+ return nil
+ }
+}
+
+const testAccCheckOneandonePrivateNetwork_basic = `
+resource "oneandone_server" "server1" {
+ name = "server_private_net_01"
+ description = "ttt"
+ image = "CoreOS_Stable_64std"
+ datacenter = "US"
+ vcores = 1
+ cores_per_processor = 1
+ ram = 2
+ password = "Kv40kd8PQb"
+ hdds = [
+ {
+ disk_size = 60
+ is_main = true
+ }
+ ]
+}
+
+resource "oneandone_server" "server2" {
+ name = "server_private_net_02"
+ description = "ttt"
+ image = "CoreOS_Stable_64std"
+ datacenter = "US"
+ vcores = 1
+ cores_per_processor = 1
+ ram = 2
+ password = "${oneandone_server.server1.password}"
+ hdds = [
+ {
+ disk_size = 60
+ is_main = true
+ }
+ ]
+}
+
+resource "oneandone_private_network" "pn" {
+ name = "%s",
+ description = "new private net"
+ datacenter = "US"
+ network_address = "192.168.7.0"
+ subnet_mask = "255.255.255.0"
+ server_ids = [
+ "${oneandone_server.server1.id}",
+ "${oneandone_server.server2.id}"
+ ]
+}
+`
diff --git a/builtin/providers/oneandone/resource_oneandone_public_ip.go b/builtin/providers/oneandone/resource_oneandone_public_ip.go
new file mode 100644
index 000000000..2c1bec240
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_public_ip.go
@@ -0,0 +1,133 @@
+package oneandone
+
+import (
+ "fmt"
+ "github.com/hashicorp/terraform/helper/schema"
+ "strings"
+)
+
+func resourceOneandOnePublicIp() *schema.Resource {
+ return &schema.Resource{
+
+ Create: resourceOneandOnePublicIpCreate,
+ Read: resourceOneandOnePublicIpRead,
+ Update: resourceOneandOnePublicIpUpdate,
+ Delete: resourceOneandOnePublicIpDelete,
+ Schema: map[string]*schema.Schema{
+ "ip_type": { //IPV4 or IPV6
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "reverse_dns": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "datacenter": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "ip_address": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ }
+}
+
+func resourceOneandOnePublicIpCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ var reverse_dns string
+ var datacenter_id string
+
+ if raw, ok := d.GetOk("reverse_dns"); ok {
+ reverse_dns = raw.(string)
+ }
+
+ if raw, ok := d.GetOk("datacenter"); ok {
+ dcs, err := config.API.ListDatacenters()
+
+ if err != nil {
+ return fmt.Errorf("An error occured while fetching list of datacenters %s", err)
+
+ }
+
+ decenter := raw.(string)
+ for _, dc := range dcs {
+ if strings.ToLower(dc.CountryCode) == strings.ToLower(decenter) {
+ datacenter_id = dc.Id
+ break
+ }
+ }
+
+ }
+
+ ip_id, ip, err := config.API.CreatePublicIp(d.Get("ip_type").(string), reverse_dns, datacenter_id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(ip, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ d.SetId(ip_id)
+
+ return resourceOneandOnePublicIpRead(d, meta)
+}
+
+func resourceOneandOnePublicIpRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ ip, err := config.API.GetPublicIp(d.Id())
+ if err != nil {
+ if strings.Contains(err.Error(), "404") {
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ d.Set("ip_address", ip.IpAddress)
+ d.Set("revers_dns", ip.ReverseDns)
+ d.Set("datacenter", ip.Datacenter.CountryCode)
+ d.Set("ip_type", ip.Type)
+
+ return nil
+}
+
+func resourceOneandOnePublicIpUpdate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ if d.HasChange("reverse_dns") {
+ _, n := d.GetChange("reverse_dns")
+ ip, err := config.API.UpdatePublicIp(d.Id(), n.(string))
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(ip, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+
+ return resourceOneandOnePublicIpRead(d, meta)
+}
+
+func resourceOneandOnePublicIpDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ ip, err := config.API.DeletePublicIp(d.Id())
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitUntilDeleted(ip)
+ if err != nil {
+
+ return err
+ }
+
+ return nil
+}
diff --git a/builtin/providers/oneandone/resource_oneandone_public_ip_test.go b/builtin/providers/oneandone/resource_oneandone_public_ip_test.go
new file mode 100644
index 000000000..c797dc666
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_public_ip_test.go
@@ -0,0 +1,119 @@
+package oneandone
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ "os"
+ "time"
+)
+
+func TestAccOneandonePublicIp_Basic(t *testing.T) {
+ var public_ip oneandone.PublicIp
+
+ reverse_dns := "example.de"
+ reverse_dns_updated := "example.ba"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDOneandonePublicIpDestroyCheck,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandonePublicIp_basic, reverse_dns),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandonePublicIpExists("oneandone_public_ip.ip", &public_ip),
+ testAccCheckOneandonePublicIpAttributes("oneandone_public_ip.ip", reverse_dns),
+ resource.TestCheckResourceAttr("oneandone_public_ip.ip", "reverse_dns", reverse_dns),
+ ),
+ },
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandonePublicIp_basic, reverse_dns_updated),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandonePublicIpExists("oneandone_public_ip.ip", &public_ip),
+ testAccCheckOneandonePublicIpAttributes("oneandone_public_ip.ip", reverse_dns_updated),
+ resource.TestCheckResourceAttr("oneandone_public_ip.ip", "reverse_dns", reverse_dns_updated),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckDOneandonePublicIpDestroyCheck(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "oneandone_public_ip" {
+ continue
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ _, err := api.GetPublicIp(rs.Primary.ID)
+
+ if err == nil {
+ return fmt.Errorf("Public IP still exists %s %s", rs.Primary.ID, err.Error())
+ }
+ }
+
+ return nil
+}
+func testAccCheckOneandonePublicIpAttributes(n string, reverse_dns string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+ if rs.Primary.Attributes["reverse_dns"] != reverse_dns {
+ return fmt.Errorf("Bad name: expected %s : found %s ", reverse_dns, rs.Primary.Attributes["name"])
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckOneandonePublicIpExists(n string, public_ip *oneandone.PublicIp) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No Record ID is set")
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ found_public_ip, err := api.GetPublicIp(rs.Primary.ID)
+
+ if err != nil {
+ return fmt.Errorf("Error occured while fetching public IP: %s", rs.Primary.ID)
+ }
+ if found_public_ip.Id != rs.Primary.ID {
+ return fmt.Errorf("Record not found")
+ }
+ public_ip = found_public_ip
+
+ return nil
+ }
+}
+
+const testAccCheckOneandonePublicIp_basic = `
+resource "oneandone_public_ip" "ip" {
+ "ip_type" = "IPV4"
+ "reverse_dns" = "%s"
+ "datacenter" = "GB"
+}`
diff --git a/builtin/providers/oneandone/resource_oneandone_server.go b/builtin/providers/oneandone/resource_oneandone_server.go
new file mode 100644
index 000000000..930aba41a
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_server.go
@@ -0,0 +1,562 @@
+package oneandone
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/schema"
+ "golang.org/x/crypto/ssh"
+ "io/ioutil"
+ "log"
+ "strings"
+
+ "errors"
+)
+
+func resourceOneandOneServer() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceOneandOneServerCreate,
+ Read: resourceOneandOneServerRead,
+ Update: resourceOneandOneServerUpdate,
+ Delete: resourceOneandOneServerDelete,
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "image": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "vcores": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "cores_per_processor": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "ram": {
+ Type: schema.TypeFloat,
+ Required: true,
+ },
+ "ssh_key_path": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "password": {
+ Type: schema.TypeString,
+ Optional: true,
+ Sensitive: true,
+ },
+ "datacenter": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "ip": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "ips": {
+ Type: schema.TypeList,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "ip": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "firewall_policy_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ },
+ },
+ Computed: true,
+ },
+ "hdds": {
+ Type: schema.TypeList,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "disk_size": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "is_main": {
+ Type: schema.TypeBool,
+ Optional: true,
+ },
+ },
+ },
+ Required: true,
+ },
+ "firewall_policy_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "monitoring_policy_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "loadbalancer_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ },
+ }
+}
+
+func resourceOneandOneServerCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ saps, _ := config.API.ListServerAppliances()
+
+ var sa oneandone.ServerAppliance
+ for _, a := range saps {
+
+ if a.Type == "IMAGE" && strings.Contains(strings.ToLower(a.Name), strings.ToLower(d.Get("image").(string))) {
+ sa = a
+ break
+ }
+ }
+
+ var hdds []oneandone.Hdd
+ if raw, ok := d.GetOk("hdds"); ok {
+ rawhdds := raw.([]interface{})
+
+ var istheremain bool
+ for _, raw := range rawhdds {
+ hd := raw.(map[string]interface{})
+ hdd := oneandone.Hdd{
+ Size: hd["disk_size"].(int),
+ IsMain: hd["is_main"].(bool),
+ }
+
+ if hdd.IsMain {
+ if hdd.Size < sa.MinHddSize {
+ return fmt.Errorf(fmt.Sprintf("Minimum required disk size %d", sa.MinHddSize))
+ }
+ istheremain = true
+ }
+
+ hdds = append(hdds, hdd)
+ }
+
+ if !istheremain {
+ return fmt.Errorf("At least one HDD has to be %s", "`is_main`")
+ }
+ }
+
+ req := oneandone.ServerRequest{
+ Name: d.Get("name").(string),
+ Description: d.Get("description").(string),
+ ApplianceId: sa.Id,
+ PowerOn: true,
+ Hardware: oneandone.Hardware{
+ Vcores: d.Get("vcores").(int),
+ CoresPerProcessor: d.Get("cores_per_processor").(int),
+ Ram: float32(d.Get("ram").(float64)),
+ Hdds: hdds,
+ },
+ }
+
+ if raw, ok := d.GetOk("ip"); ok {
+
+ new_ip := raw.(string)
+
+ ips, err := config.API.ListPublicIps()
+ if err != nil {
+ return err
+ }
+
+ for _, ip := range ips {
+ if ip.IpAddress == new_ip {
+ req.IpId = ip.Id
+ break
+ }
+ }
+
+ log.Println("[DEBUG] req.IP", req.IpId)
+ }
+
+ if raw, ok := d.GetOk("datacenter"); ok {
+
+ dcs, err := config.API.ListDatacenters()
+
+ if err != nil {
+ return fmt.Errorf("An error occured while fetching list of datacenters %s", err)
+
+ }
+
+ decenter := raw.(string)
+ for _, dc := range dcs {
+ if strings.ToLower(dc.CountryCode) == strings.ToLower(decenter) {
+ req.DatacenterId = dc.Id
+ break
+ }
+ }
+ }
+
+ if fwp_id, ok := d.GetOk("firewall_policy_id"); ok {
+ req.FirewallPolicyId = fwp_id.(string)
+ }
+
+ if mp_id, ok := d.GetOk("monitoring_policy_id"); ok {
+ req.MonitoringPolicyId = mp_id.(string)
+ }
+
+ if mp_id, ok := d.GetOk("loadbalancer_id"); ok {
+ req.LoadBalancerId = mp_id.(string)
+ }
+
+ var privateKey string
+ if raw, ok := d.GetOk("ssh_key_path"); ok {
+ rawpath := raw.(string)
+
+ priv, publicKey, err := getSshKey(rawpath)
+ privateKey = priv
+ if err != nil {
+ return err
+ }
+
+ req.SSHKey = publicKey
+ }
+
+ var password string
+ if raw, ok := d.GetOk("password"); ok {
+ req.Password = raw.(string)
+ password = req.Password
+ }
+
+ server_id, server, err := config.API.CreateServer(&req)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(server, "POWERED_ON", 10, config.Retries)
+
+ d.SetId(server_id)
+ server, err = config.API.GetServer(d.Id())
+ if err != nil {
+ return err
+ }
+
+ if password == "" {
+ password = server.FirstPassword
+ }
+ d.SetConnInfo(map[string]string{
+ "type": "ssh",
+ "host": server.Ips[0].Ip,
+ "password": password,
+ "private_key": privateKey,
+ })
+
+ return resourceOneandOneServerRead(d, meta)
+}
+
+func resourceOneandOneServerRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ server, err := config.API.GetServer(d.Id())
+
+ if err != nil {
+ if strings.Contains(err.Error(), "404") {
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ d.Set("name", server.Name)
+ d.Set("datacenter", server.Datacenter.CountryCode)
+
+ d.Set("hdds", readHdds(server.Hardware))
+
+ d.Set("ips", readIps(server.Ips))
+
+ if len(server.FirstPassword) > 0 {
+ d.Set("password", server.FirstPassword)
+ }
+
+ return nil
+}
+
+func resourceOneandOneServerUpdate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ if d.HasChange("name") || d.HasChange("description") {
+ _, name := d.GetChange("name")
+ _, description := d.GetChange("description")
+ server, err := config.API.RenameServer(d.Id(), name.(string), description.(string))
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(server, "POWERED_ON", 10, config.Retries)
+
+ }
+
+ if d.HasChange("hdds") {
+ oldV, newV := d.GetChange("hdds")
+ newValues := newV.([]interface{})
+ oldValues := oldV.([]interface{})
+
+ if len(oldValues) > len(newValues) {
+ diff := difference(oldValues, newValues)
+ for _, old := range diff {
+ o := old.(map[string]interface{})
+ old_id := o["id"].(string)
+ server, err := config.API.DeleteServerHdd(d.Id(), old_id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(server, "POWERED_ON", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ for _, newHdd := range newValues {
+ n := newHdd.(map[string]interface{})
+ //old := oldHdd.(map[string]interface{})
+
+ if n["id"].(string) == "" {
+ hdds := oneandone.ServerHdds{
+ Hdds: []oneandone.Hdd{
+ {
+ Size: n["disk_size"].(int),
+ IsMain: n["is_main"].(bool),
+ },
+ },
+ }
+
+ server, err := config.API.AddServerHdds(d.Id(), &hdds)
+
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(server, "POWERED_ON", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ } else {
+ id := n["id"].(string)
+ isMain := n["is_main"].(bool)
+
+ if id != "" && !isMain {
+ log.Println("[DEBUG] Resizing existing HDD")
+ config.API.ResizeServerHdd(d.Id(), id, n["disk_size"].(int))
+ }
+ }
+
+ }
+ }
+ }
+
+ if d.HasChange("monitoring_policy_id") {
+ o, n := d.GetChange("monitoring_policy_id")
+
+ if n == nil {
+ mp, err := config.API.RemoveMonitoringPolicyServer(o.(string), d.Id())
+
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ } else {
+ mp, err := config.API.AttachMonitoringPolicyServers(n.(string), []string{d.Id()})
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ if d.HasChange("loadbalancer_id") {
+ o, n := d.GetChange("loadbalancer_id")
+ server, err := config.API.GetServer(d.Id())
+ if err != nil {
+ return err
+ }
+
+ if n == nil || n.(string) == "" {
+ log.Println("[DEBUG] Removing")
+ log.Println("[DEBUG] IPS:", server.Ips)
+
+ for _, ip := range server.Ips {
+ mp, err := config.API.DeleteLoadBalancerServerIp(o.(string), ip.Id)
+
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ log.Println("[DEBUG] Adding")
+ ip_ids := []string{}
+ for _, ip := range server.Ips {
+ ip_ids = append(ip_ids, ip.Id)
+ }
+ mp, err := config.API.AddLoadBalancerServerIps(n.(string), ip_ids)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ }
+ }
+
+ if d.HasChange("firewall_policy_id") {
+ server, err := config.API.GetServer(d.Id())
+ if err != nil {
+ return err
+ }
+
+ o, n := d.GetChange("firewall_policy_id")
+ if n == nil {
+ for _, ip := range server.Ips {
+ mp, err := config.API.DeleteFirewallPolicyServerIp(o.(string), ip.Id)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ ip_ids := []string{}
+ for _, ip := range server.Ips {
+ ip_ids = append(ip_ids, ip.Id)
+ }
+
+ mp, err := config.API.AddFirewallPolicyServerIps(n.(string), ip_ids)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(mp, "ACTIVE", 30, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return resourceOneandOneServerRead(d, meta)
+}
+
+func resourceOneandOneServerDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ _, ok := d.GetOk("ip")
+
+ server, err := config.API.DeleteServer(d.Id(), ok)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitUntilDeleted(server)
+
+ if err != nil {
+ log.Println("[DEBUG] ************ ERROR While waiting ************")
+ return err
+ }
+ return nil
+}
+
+func readHdds(hardware *oneandone.Hardware) []map[string]interface{} {
+ hdds := make([]map[string]interface{}, 0, len(hardware.Hdds))
+
+ for _, hd := range hardware.Hdds {
+ hdds = append(hdds, map[string]interface{}{
+ "id": hd.Id,
+ "disk_size": hd.Size,
+ "is_main": hd.IsMain,
+ })
+ }
+
+ return hdds
+}
+
+func readIps(ips []oneandone.ServerIp) []map[string]interface{} {
+ raw := make([]map[string]interface{}, 0, len(ips))
+ for _, ip := range ips {
+
+ toadd := map[string]interface{}{
+ "ip": ip.Ip,
+ "id": ip.Id,
+ }
+
+ if ip.Firewall != nil {
+ toadd["firewall_policy_id"] = ip.Firewall.Id
+ }
+ raw = append(raw, toadd)
+ }
+
+ return raw
+}
+
+func getSshKey(path string) (privatekey string, publickey string, err error) {
+ pemBytes, err := ioutil.ReadFile(path)
+
+ if err != nil {
+ return "", "", err
+ }
+
+ block, _ := pem.Decode(pemBytes)
+
+ if block == nil {
+ return "", "", errors.New("File " + path + " contains nothing")
+ }
+
+ priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+
+ if err != nil {
+ return "", "", err
+ }
+
+ priv_blk := pem.Block{
+ Type: "RSA PRIVATE KEY",
+ Headers: nil,
+ Bytes: x509.MarshalPKCS1PrivateKey(priv),
+ }
+
+ pub, err := ssh.NewPublicKey(&priv.PublicKey)
+ if err != nil {
+ return "", "", err
+ }
+ publickey = string(ssh.MarshalAuthorizedKey(pub))
+ privatekey = string(pem.EncodeToMemory(&priv_blk))
+
+ return privatekey, publickey, nil
+}
diff --git a/builtin/providers/oneandone/resource_oneandone_server_test.go b/builtin/providers/oneandone/resource_oneandone_server_test.go
new file mode 100644
index 000000000..ed643abfa
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_server_test.go
@@ -0,0 +1,130 @@
+package oneandone
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ "os"
+ "time"
+)
+
+func TestAccOneandoneServer_Basic(t *testing.T) {
+ var server oneandone.Server
+
+ name := "test_server"
+ name_updated := "test_server_renamed"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDOneandoneServerDestroyCheck,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneServer_basic, name, name),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneServerExists("oneandone_server.server", &server),
+ testAccCheckOneandoneServerAttributes("oneandone_server.server", name),
+ resource.TestCheckResourceAttr("oneandone_server.server", "name", name),
+ ),
+ },
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneServer_basic, name_updated, name_updated),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneServerExists("oneandone_server.server", &server),
+ testAccCheckOneandoneServerAttributes("oneandone_server.server", name_updated),
+ resource.TestCheckResourceAttr("oneandone_server.server", "name", name_updated),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckDOneandoneServerDestroyCheck(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "oneandone_server" {
+ continue
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ _, err := api.GetServer(rs.Primary.ID)
+
+ if err == nil {
+ return fmt.Errorf("Server still exists %s %s", rs.Primary.ID, err.Error())
+ }
+ }
+
+ return nil
+}
+func testAccCheckOneandoneServerAttributes(n string, reverse_dns string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+ if rs.Primary.Attributes["name"] != reverse_dns {
+ return fmt.Errorf("Bad name: expected %s : found %s ", reverse_dns, rs.Primary.Attributes["name"])
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckOneandoneServerExists(n string, server *oneandone.Server) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No Record ID is set")
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ found_server, err := api.GetServer(rs.Primary.ID)
+
+ if err != nil {
+ return fmt.Errorf("Error occured while fetching Server: %s", rs.Primary.ID)
+ }
+ if found_server.Id != rs.Primary.ID {
+ return fmt.Errorf("Record not found")
+ }
+ server = found_server
+
+ return nil
+ }
+}
+
+const testAccCheckOneandoneServer_basic = `
+resource "oneandone_server" "server" {
+ name = "%s"
+ description = "%s"
+ image = "ubuntu"
+ datacenter = "GB"
+ vcores = 1
+ cores_per_processor = 1
+ ram = 2
+ password = "Kv40kd8PQb"
+ hdds = [
+ {
+ disk_size = 20
+ is_main = true
+ }
+ ]
+}`
diff --git a/builtin/providers/oneandone/resource_oneandone_vpn.go b/builtin/providers/oneandone/resource_oneandone_vpn.go
new file mode 100644
index 000000000..865c3361a
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_vpn.go
@@ -0,0 +1,217 @@
+package oneandone
+
+import (
+ "crypto/md5"
+ "encoding/base64"
+ "fmt"
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/schema"
+ "io"
+ "os"
+ fp "path/filepath"
+ "strings"
+)
+
+func resourceOneandOneVPN() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceOneandOneVPNCreate,
+ Read: resourceOneandOneVPNRead,
+ Update: resourceOneandOneVPNUpdate,
+ Delete: resourceOneandOneVPNDelete,
+ Schema: map[string]*schema.Schema{
+
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "download_path": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "datacenter": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "file_name": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ }
+}
+
+func resourceOneandOneVPNCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ var datacenter string
+
+ if raw, ok := d.GetOk("datacenter"); ok {
+ dcs, err := config.API.ListDatacenters()
+ if err != nil {
+ return fmt.Errorf("An error occured while fetching list of datacenters %s", err)
+ }
+
+ decenter := raw.(string)
+ for _, dc := range dcs {
+ if strings.ToLower(dc.CountryCode) == strings.ToLower(decenter) {
+ datacenter = dc.Id
+ break
+ }
+ }
+ }
+
+ var description string
+ if raw, ok := d.GetOk("description"); ok {
+ description = raw.(string)
+ }
+
+ vpn_id, vpn, err := config.API.CreateVPN(d.Get("name").(string), description, datacenter)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(vpn, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+
+ d.SetId(vpn_id)
+
+ return resourceOneandOneVPNRead(d, meta)
+}
+
+func resourceOneandOneVPNUpdate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ if d.HasChange("name") || d.HasChange("description") {
+
+ vpn, err := config.API.ModifyVPN(d.Id(), d.Get("name").(string), d.Get("description").(string))
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(vpn, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ }
+
+ return resourceOneandOneVPNRead(d, meta)
+}
+
+func resourceOneandOneVPNRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ vpn, err := config.API.GetVPN(d.Id())
+
+ base64_str, err := config.API.GetVPNConfigFile(d.Id())
+ if err != nil {
+ if strings.Contains(err.Error(), "404") {
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ var download_path string
+ if raw, ok := d.GetOk("download_path"); ok {
+ download_path = raw.(string)
+ }
+
+ path, fileName, err := writeCofnig(vpn, download_path, base64_str)
+ if err != nil {
+ return err
+ }
+
+ d.Set("name", vpn.Name)
+ d.Set("description", vpn.Description)
+ d.Set("download_path", path)
+ d.Set("file_name", fileName)
+ d.Set("datacenter", vpn.Datacenter.CountryCode)
+
+ return nil
+}
+
+func writeCofnig(vpn *oneandone.VPN, path, base64config string) (string, string, error) {
+ data, err := base64.StdEncoding.DecodeString(base64config)
+ if err != nil {
+ return "", "", err
+ }
+
+ var fileName string
+ if vpn.CloudPanelId != "" {
+ fileName = vpn.CloudPanelId + ".zip"
+ } else {
+ fileName = "vpn_" + fmt.Sprintf("%x", md5.Sum(data)) + ".zip"
+ }
+
+ if path == "" {
+ path, err = os.Getwd()
+ if err != nil {
+ return "", "", err
+ }
+ }
+
+ if !fp.IsAbs(path) {
+ path, err = fp.Abs(path)
+ if err != nil {
+ return "", "", err
+ }
+ }
+
+ _, err = os.Stat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ // make all dirs
+ os.MkdirAll(path, 0666)
+ } else {
+ return "", "", err
+ }
+ }
+
+ fpath := fp.Join(path, fileName)
+
+ f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY, 0666)
+ defer f.Close()
+
+ if err != nil {
+ return "", "", err
+ }
+
+ n, err := f.Write(data)
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+
+ if err != nil {
+ return "", "", err
+ }
+
+ return path, fileName, nil
+
+}
+
+func resourceOneandOneVPNDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ vpn, err := config.API.DeleteVPN(d.Id())
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitUntilDeleted(vpn)
+ if err != nil {
+ return err
+ }
+
+ fullPath := fp.Join(d.Get("download_path").(string), d.Get("file_name").(string))
+ if _, err := os.Stat(fullPath); !os.IsNotExist(err) {
+ os.Remove(fullPath)
+ }
+
+ return nil
+}
diff --git a/builtin/providers/oneandone/resource_oneandone_vpn_test.go b/builtin/providers/oneandone/resource_oneandone_vpn_test.go
new file mode 100644
index 000000000..94e84bb61
--- /dev/null
+++ b/builtin/providers/oneandone/resource_oneandone_vpn_test.go
@@ -0,0 +1,119 @@
+package oneandone
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ "os"
+ "time"
+)
+
+func TestAccOneandoneVpn_Basic(t *testing.T) {
+ var server oneandone.VPN
+
+ name := "test"
+ name_updated := "test1"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDOneandoneVPNDestroyCheck,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneVPN_basic, name),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneVPNExists("oneandone_vpn.vpn", &server),
+ testAccCheckOneandoneVPNAttributes("oneandone_vpn.vpn", name),
+ resource.TestCheckResourceAttr("oneandone_vpn.vpn", "name", name),
+ ),
+ },
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneVPN_basic, name_updated),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneVPNExists("oneandone_vpn.vpn", &server),
+ testAccCheckOneandoneVPNAttributes("oneandone_vpn.vpn", name_updated),
+ resource.TestCheckResourceAttr("oneandone_vpn.vpn", "name", name_updated),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckDOneandoneVPNDestroyCheck(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "oneandone_server" {
+ continue
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ _, err := api.GetVPN(rs.Primary.ID)
+
+ if err == nil {
+ return fmt.Errorf("VPN still exists %s %s", rs.Primary.ID, err.Error())
+ }
+ }
+
+ return nil
+}
+func testAccCheckOneandoneVPNAttributes(n string, reverse_dns string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+ if rs.Primary.Attributes["name"] != reverse_dns {
+ return fmt.Errorf("Bad name: expected %s : found %s ", reverse_dns, rs.Primary.Attributes["name"])
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckOneandoneVPNExists(n string, server *oneandone.VPN) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No Record ID is set")
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ found_server, err := api.GetVPN(rs.Primary.ID)
+
+ if err != nil {
+ return fmt.Errorf("Error occured while fetching VPN: %s", rs.Primary.ID)
+ }
+ if found_server.Id != rs.Primary.ID {
+ return fmt.Errorf("Record not found")
+ }
+ server = found_server
+
+ return nil
+ }
+}
+
+const testAccCheckOneandoneVPN_basic = `
+resource "oneandone_vpn" "vpn" {
+ datacenter = "GB"
+ name = "%s"
+ description = "ttest descr"
+}`
diff --git a/builtin/providers/oneandone/resources_oneandone_shared_storage.go b/builtin/providers/oneandone/resources_oneandone_shared_storage.go
new file mode 100644
index 000000000..f690e0cf6
--- /dev/null
+++ b/builtin/providers/oneandone/resources_oneandone_shared_storage.go
@@ -0,0 +1,256 @@
+package oneandone
+
+import (
+ "fmt"
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/schema"
+ "strings"
+)
+
+func resourceOneandOneSharedStorage() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceOneandOneSharedStorageCreate,
+ Read: resourceOneandOneSharedStorageRead,
+ Update: resourceOneandOneSharedStorageUpdate,
+ Delete: resourceOneandOneSharedStorageDelete,
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "description": {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ "size": {
+ Type: schema.TypeInt,
+ Required: true,
+ },
+ "datacenter": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "storage_servers": {
+ Type: schema.TypeList,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "rights": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ },
+ },
+ Optional: true,
+ },
+ },
+ }
+}
+
+func resourceOneandOneSharedStorageCreate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ req := oneandone.SharedStorageRequest{
+ Name: d.Get("name").(string),
+ Size: oneandone.Int2Pointer(d.Get("size").(int)),
+ }
+
+ if raw, ok := d.GetOk("description"); ok {
+ req.Description = raw.(string)
+
+ }
+
+ if raw, ok := d.GetOk("datacenter"); ok {
+ dcs, err := config.API.ListDatacenters()
+
+ if err != nil {
+ return fmt.Errorf("An error occured while fetching list of datacenters %s", err)
+
+ }
+
+ decenter := raw.(string)
+ for _, dc := range dcs {
+ if strings.ToLower(dc.CountryCode) == strings.ToLower(decenter) {
+ req.DatacenterId = dc.Id
+ break
+ }
+ }
+ }
+
+ ss_id, ss, err := config.API.CreateSharedStorage(&req)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(ss, "ACTIVE", 10, config.Retries)
+ if err != nil {
+ return err
+ }
+ d.SetId(ss_id)
+
+ if raw, ok := d.GetOk("storage_servers"); ok {
+
+ storage_servers := []oneandone.SharedStorageServer{}
+
+ rawRights := raw.([]interface{})
+ for _, raws_ss := range rawRights {
+ ss := raws_ss.(map[string]interface{})
+ storage_server := oneandone.SharedStorageServer{
+ Id: ss["id"].(string),
+ Rights: ss["rights"].(string),
+ }
+ storage_servers = append(storage_servers, storage_server)
+ }
+
+ ss, err := config.API.AddSharedStorageServers(ss_id, storage_servers)
+
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(ss, "ACTIVE", 10, 30)
+ if err != nil {
+ return err
+ }
+ }
+
+ return resourceOneandOneSharedStorageRead(d, meta)
+}
+
+func resourceOneandOneSharedStorageUpdate(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ if d.HasChange("name") || d.HasChange("description") || d.HasChange("size") {
+ ssu := oneandone.SharedStorageRequest{}
+ if d.HasChange("name") {
+ _, n := d.GetChange("name")
+ ssu.Name = n.(string)
+ }
+ if d.HasChange("description") {
+ _, n := d.GetChange("description")
+ ssu.Description = n.(string)
+ }
+ if d.HasChange("size") {
+ _, n := d.GetChange("size")
+ ssu.Size = oneandone.Int2Pointer(n.(int))
+ }
+
+ ss, err := config.API.UpdateSharedStorage(d.Id(), &ssu)
+
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitForState(ss, "ACTIVE", 10, 30)
+ if err != nil {
+ return err
+ }
+
+ }
+
+ if d.HasChange("storage_servers") {
+
+ o, n := d.GetChange("storage_servers")
+
+ oldV := o.([]interface{})
+
+ for _, old := range oldV {
+ ol := old.(map[string]interface{})
+
+ ss, err := config.API.DeleteSharedStorageServer(d.Id(), ol["id"].(string))
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(ss, "ACTIVE", 10, config.Retries)
+
+ if err != nil {
+ return err
+ }
+
+ }
+
+ newV := n.([]interface{})
+
+ ids := []oneandone.SharedStorageServer{}
+ for _, newValue := range newV {
+ nn := newValue.(map[string]interface{})
+ ids = append(ids, oneandone.SharedStorageServer{
+ Id: nn["id"].(string),
+ Rights: nn["rights"].(string),
+ })
+ }
+
+ if len(ids) > 0 {
+ ss, err := config.API.AddSharedStorageServers(d.Id(), ids)
+ if err != nil {
+ return err
+ }
+
+ err = config.API.WaitForState(ss, "ACTIVE", 10, config.Retries)
+
+ if err != nil {
+ return err
+ }
+ }
+
+ //DeleteSharedStorageServer
+
+ }
+
+ return resourceOneandOneSharedStorageRead(d, meta)
+}
+
+func resourceOneandOneSharedStorageRead(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ ss, err := config.API.GetSharedStorage(d.Id())
+ if err != nil {
+ if strings.Contains(err.Error(), "404") {
+ d.SetId("")
+ return nil
+ }
+ return err
+ }
+
+ d.Set("name", ss.Name)
+ d.Set("description", ss.Description)
+ d.Set("size", ss.Size)
+ d.Set("datacenter", ss.Datacenter.CountryCode)
+ d.Set("storage_servers", getStorageServers(ss.Servers))
+
+ return nil
+}
+
+func getStorageServers(servers []oneandone.SharedStorageServer) []map[string]interface{} {
+ raw := make([]map[string]interface{}, 0, len(servers))
+
+ for _, server := range servers {
+
+ toadd := map[string]interface{}{
+ "id": server.Id,
+ "rights": server.Rights,
+ }
+
+ raw = append(raw, toadd)
+ }
+
+ return raw
+
+}
+func resourceOneandOneSharedStorageDelete(d *schema.ResourceData, meta interface{}) error {
+ config := meta.(*Config)
+
+ ss, err := config.API.DeleteSharedStorage(d.Id())
+ if err != nil {
+ return err
+ }
+ err = config.API.WaitUntilDeleted(ss)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/builtin/providers/oneandone/resources_oneandone_shared_storage_test.go b/builtin/providers/oneandone/resources_oneandone_shared_storage_test.go
new file mode 100644
index 000000000..dcc07302a
--- /dev/null
+++ b/builtin/providers/oneandone/resources_oneandone_shared_storage_test.go
@@ -0,0 +1,120 @@
+package oneandone
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+ "os"
+ "time"
+)
+
+func TestAccOneandoneSharedStorage_Basic(t *testing.T) {
+ var storage oneandone.SharedStorage
+
+ name := "test_storage"
+ name_updated := "test1"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() {
+ testAccPreCheck(t)
+ },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckDOneandoneSharedStorageDestroyCheck,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneSharedStorage_basic, name),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneSharedStorageExists("oneandone_shared_storage.storage", &storage),
+ testAccCheckOneandoneSharedStorageAttributes("oneandone_shared_storage.storage", name),
+ resource.TestCheckResourceAttr("oneandone_shared_storage.storage", "name", name),
+ ),
+ },
+ resource.TestStep{
+ Config: fmt.Sprintf(testAccCheckOneandoneSharedStorage_basic, name_updated),
+ Check: resource.ComposeTestCheckFunc(
+ func(*terraform.State) error {
+ time.Sleep(10 * time.Second)
+ return nil
+ },
+ testAccCheckOneandoneSharedStorageExists("oneandone_shared_storage.storage", &storage),
+ testAccCheckOneandoneSharedStorageAttributes("oneandone_shared_storage.storage", name_updated),
+ resource.TestCheckResourceAttr("oneandone_shared_storage.storage", "name", name_updated),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckDOneandoneSharedStorageDestroyCheck(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "oneandone_shared_storage" {
+ continue
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ _, err := api.GetVPN(rs.Primary.ID)
+
+ if err == nil {
+ return fmt.Errorf("VPN still exists %s %s", rs.Primary.ID, err.Error())
+ }
+ }
+
+ return nil
+}
+func testAccCheckOneandoneSharedStorageAttributes(n string, reverse_dns string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+ if rs.Primary.Attributes["name"] != reverse_dns {
+ return fmt.Errorf("Bad name: expected %s : found %s ", reverse_dns, rs.Primary.Attributes["name"])
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckOneandoneSharedStorageExists(n string, storage *oneandone.SharedStorage) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[n]
+
+ if !ok {
+ return fmt.Errorf("Not found: %s", n)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No Record ID is set")
+ }
+
+ api := oneandone.New(os.Getenv("ONEANDONE_TOKEN"), oneandone.BaseUrl)
+
+ found_storage, err := api.GetSharedStorage(rs.Primary.ID)
+
+ if err != nil {
+ return fmt.Errorf("Error occured while fetching SharedStorage: %s", rs.Primary.ID)
+ }
+ if found_storage.Id != rs.Primary.ID {
+ return fmt.Errorf("Record not found")
+ }
+ storage = found_storage
+
+ return nil
+ }
+}
+
+const testAccCheckOneandoneSharedStorage_basic = `
+resource "oneandone_shared_storage" "storage" {
+ name = "%s"
+ description = "ttt"
+ size = 50
+ datacenter = "GB"
+}`
diff --git a/command/counthookaction_string.go b/command/counthookaction_string.go
index 423cae07e..c0c40d0de 100644
--- a/command/counthookaction_string.go
+++ b/command/counthookaction_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT.
+// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT
package command
diff --git a/command/internal_plugin_list.go b/command/internal_plugin_list.go
index 9e53c16b9..dfb2b9f1d 100644
--- a/command/internal_plugin_list.go
+++ b/command/internal_plugin_list.go
@@ -47,6 +47,7 @@ import (
nomadprovider "github.com/hashicorp/terraform/builtin/providers/nomad"
ns1provider "github.com/hashicorp/terraform/builtin/providers/ns1"
nullprovider "github.com/hashicorp/terraform/builtin/providers/null"
+ oneandoneprovider "github.com/hashicorp/terraform/builtin/providers/oneandone"
opcprovider "github.com/hashicorp/terraform/builtin/providers/opc"
openstackprovider "github.com/hashicorp/terraform/builtin/providers/openstack"
opsgenieprovider "github.com/hashicorp/terraform/builtin/providers/opsgenie"
@@ -126,6 +127,7 @@ var InternalProviders = map[string]plugin.ProviderFunc{
"ns1": ns1provider.Provider,
"null": nullprovider.Provider,
"opc": opcprovider.Provider,
+ "oneandone": oneandoneprovider.Provider,
"openstack": openstackprovider.Provider,
"opsgenie": opsgenieprovider.Provider,
"packet": packetprovider.Provider,
diff --git a/config/resource_mode_string.go b/config/resource_mode_string.go
index ea68b4fcd..930645fa8 100644
--- a/config/resource_mode_string.go
+++ b/config/resource_mode_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT.
+// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT
package config
diff --git a/helper/schema/getsource_string.go b/helper/schema/getsource_string.go
index 3a9762939..790dbff91 100644
--- a/helper/schema/getsource_string.go
+++ b/helper/schema/getsource_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT.
+// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT
package schema
diff --git a/helper/schema/valuetype_string.go b/helper/schema/valuetype_string.go
index 1610cec2d..08f008450 100644
--- a/helper/schema/valuetype_string.go
+++ b/helper/schema/valuetype_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT.
+// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT
package schema
diff --git a/terraform/graphtype_string.go b/terraform/graphtype_string.go
index e97b4855a..88ecad4f6 100644
--- a/terraform/graphtype_string.go
+++ b/terraform/graphtype_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT.
+// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT
package terraform
diff --git a/terraform/instancetype_string.go b/terraform/instancetype_string.go
index f69267cd5..f65414b34 100644
--- a/terraform/instancetype_string.go
+++ b/terraform/instancetype_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT.
+// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT
package terraform
diff --git a/terraform/walkoperation_string.go b/terraform/walkoperation_string.go
index cbd78dd93..8fb33d7b5 100644
--- a/terraform/walkoperation_string.go
+++ b/terraform/walkoperation_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT.
+// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT
package terraform
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/LICENSE b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/LICENSE
new file mode 100644
index 000000000..9fb7e22bc
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/LICENSE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright (c) 2016 1&1 Internet SE
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/README.md b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/README.md
new file mode 100644
index 000000000..adb9cd19b
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/README.md
@@ -0,0 +1,2573 @@
+# 1&1 Cloudserver Go SDK
+
+The 1&1 Go SDK is a Go library designed for interaction with the 1&1 cloud platform over the REST API.
+
+This guide contains instructions on getting started with the library and automating various management tasks available through the 1&1 Cloud Panel UI.
+
+## Table of Contents
+
+- [Overview](#overview)
+- [Getting Started](#getting-started)
+ - [Installation](#installation)
+ - [Authentication](#authentication)
+- [Operations](#operations)
+ - [Servers](#servers)
+ - [Images](#images)
+ - [Shared Storages](#shared-storages)
+ - [Firewall Policies](#firewall-policies)
+ - [Load Balancers](#load-balancers)
+ - [Public IPs](#public-ips)
+ - [Private Networks](#private-networks)
+ - [VPNs](#vpns)
+ - [Monitoring Center](#monitoring-center)
+ - [Monitoring Policies](#monitoring-policies)
+ - [Logs](#logs)
+ - [Users](#users)
+ - [Roles](#roles)
+ - [Usages](#usages)
+ - [Server Appliances](#server-appliances)
+ - [DVD ISO](#dvd-iso)
+ - [Ping](#ping)
+ - [Pricing](#pricing)
+ - [Data Centers](#data-centers)
+- [Examples](#examples)
+- [Index](#index)
+
+## Overview
+
+This SDK is a wrapper for the 1&1 REST API written in Go(lang). All operations against the API are performed over SSL and authenticated using your 1&1 token key. The Go library facilitates the access to the REST API either within an instance running on 1&1 platform or directly across the Internet from any HTTPS-enabled application.
+
+For more information on the 1&1 Cloud Server SDK for Go, visit the [Community Portal](https://www.1and1.com/cloud-community/).
+
+## Getting Started
+
+Before you begin you will need to have signed up for a 1&1 account. The credentials you create during sign-up will be used to authenticate against the API.
+
+Install the Go language tools. Find the install package and instructions on the official Go website. Make sure that you have set up the `GOPATH` environment variable properly, as indicated in the instructions.
+
+### Installation
+
+The official Go library is available from the 1&1 GitHub account found here.
+
+Use the following Go command to download oneandone-cloudserver-sdk-go to your configured GOPATH:
+
+`go get github.com/1and1/oneandone-cloudserver-sdk-go`
+
+Import the library in your Go code:
+
+`import "github.com/1and1/oneandone-cloudserver-sdk-go"`
+
+### Authentication
+
+Set the authentication token and create the API client:
+
+```
+token := oneandone.SetToken("82ee732b8d47e451be5c6ad5b7b56c81")
+api := oneandone.New(token, oneandone.BaseUrl)
+```
+
+Refer to the [Examples](#examples) and [Operations](#operations) sections for additional information.
+
+## Operations
+
+### Servers
+
+**List all servers:**
+
+`servers, err := api.ListServers()`
+
+Alternatively, use the method with query parameters.
+
+`servers, err := api.ListServers(page, per_page, sort, query, fields)`
+
+To paginate the list of servers received in the response use `page` and `per_page` parameters. Set `per_page` to the number of servers that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of servers sorted in expected order pass a server property (e.g. `"name"`) in `sort` parameter.
+
+Use `query` parameter to search for a string in the response and return only the server instances that contain it.
+
+To retrieve a collection of servers containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,description,hardware.ram"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve a single server:**
+
+`server, err := api.GetServer(server_id)`
+
+**List fixed-size server templates:**
+
+`fiss, err := api.ListFixedInstanceSizes()`
+
+**Retrieve information about a fixed-size server template:**
+
+`fis, err := api.GetFixedInstanceSize(fis_id)`
+
+**Retrieve information about a server's hardware:**
+
+`hardware, err := api.GetServerHardware(server_id)`
+
+**List a server's HDDs:**
+
+`hdds, err := api.ListServerHdds(server_id)`
+
+**Retrieve a single server HDD:**
+
+`hdd, err := api.GetServerHdd(server_id, hdd_id)`
+
+**Retrieve information about a server's image:**
+
+`image, err := api.GetServerImage(server_id)`
+
+**List a server's IPs:**
+
+`ips, err := api.ListServerIps(server_id)`
+
+**Retrieve information about a single server IP:**
+
+`ip, err := api.GetServerIp(server_id, ip_id)`
+
+**Retrieve information about a server's firewall policy:**
+
+`firewall, err := api.GetServerIpFirewallPolicy(server_id, ip_id)`
+
+**List all load balancers assigned to a server IP:**
+
+`lbs, err := api.ListServerIpLoadBalancers(server_id, ip_id)`
+
+**Retrieve information about a server's status:**
+
+`status, err := api.GetServerStatus(server_id)`
+
+**Retrieve information about the DVD loaded into the virtual DVD unit of a server:**
+
+`dvd, err := api.GetServerDvd(server_id)`
+
+**List a server's private networks:**
+
+`pns, err := api.ListServerPrivateNetworks(server_id)`
+
+**Retrieve information about a server's private network:**
+
+`pn, err := api.GetServerPrivateNetwork(server_id, pn_id)`
+
+**Retrieve information about a server's snapshot:**
+
+`snapshot, err := api.GetServerSnapshot(server_id)`
+
+**Create a server:**
+
+```
+req := oneandone.ServerRequest {
+ Name: "Server Name",
+ Description: "Server description.",
+ ApplianceId: server_appliance_id,
+ PowerOn: true,
+ Hardware: oneandone.Hardware {
+ Vcores: 1,
+ CoresPerProcessor: 1,
+ Ram: 2,
+ Hdds: []oneandone.Hdd {
+ oneandone.Hdd {
+ Size: 100,
+ IsMain: true,
+ },
+ },
+ },
+ }
+
+server_id, server, err := api.CreateServer(&req)
+```
+
+**Create a fixed-size server and return back the server's IP address and first password:**
+
+```
+req := oneandone.ServerRequest {
+ Name: server_name,
+ ApplianceId: server_appliance_id,
+ PowerOn: true_or_false,
+ Hardware: oneandone.Hardware {
+ FixedInsSizeId: fixed_instance_size_id,
+ },
+ }
+
+ip_address, password, err := api.CreateServerEx(&req, timeout)
+```
+
+**Update a server:**
+
+`server, err := api.RenameServer(server_id, new_name, new_desc)`
+
+**Delete a server:**
+
+`server, err := api.DeleteServer(server_id, keep_ips)`
+
+Set `keep_ips` parameter to `true` for keeping server IPs after deleting a server.
+
+**Update a server's hardware:**
+
+```
+hardware := oneandone.Hardware {
+ Vcores: 2,
+ CoresPerProcessor: 1,
+ Ram: 2,
+ }
+
+server, err := api.UpdateServerHardware(server_id, &hardware)
+```
+
+**Add new hard disk(s) to a server:**
+
+```
+hdds := oneandone.ServerHdds {
+ Hdds: []oneandone.Hdd {
+ {
+ Size: 50,
+ IsMain: false,
+ },
+ },
+ }
+
+server, err := api.AddServerHdds(server_id, &hdds)
+```
+
+**Resize a server's hard disk:**
+
+`server, err := api.ResizeServerHdd(server_id, hdd_id, new_size)`
+
+**Remove a server's hard disk:**
+
+`server, err := api.DeleteServerHdd(server_id, hdd_id)`
+
+**Load a DVD into the virtual DVD unit of a server:**
+
+`server, err := api.LoadServerDvd(server_id, dvd_id)`
+
+**Unload a DVD from the virtual DVD unit of a server:**
+
+`server, err := api.EjectServerDvd(server_id)`
+
+**Reinstall a new image into a server:**
+
+`server, err := api.ReinstallServerImage(server_id, image_id, password, fp_id)`
+
+**Assign a new IP to a server:**
+
+`server, err := api.AssignServerIp(server_id, ip_type)`
+
+**Release an IP and optionally remove it from a server:**
+
+`server, err := api.DeleteServerIp(server_id, ip_id, keep_ip)`
+
+Set `keep_ip` to true for releasing the IP without removing it.
+
+**Assign a new firewall policy to a server's IP:**
+
+`server, err := api.AssignServerIpFirewallPolicy(server_id, ip_id, fp_id)`
+
+**Remove a firewall policy from a server's IP:**
+
+`server, err := api.UnassignServerIpFirewallPolicy(server_id, ip_id)`
+
+**Assign a new load balancer to a server's IP:**
+
+`server, err := api.AssignServerIpLoadBalancer(server_id, ip_id, lb_id)`
+
+**Remove a load balancer from a server's IP:**
+
+`server, err := api.UnassignServerIpLoadBalancer(server_id, ip_id, lb_id)`
+
+**Start a server:**
+
+`server, err := api.StartServer(server_id)`
+
+**Reboot a server:**
+
+`server, err := api.RebootServer(server_id, is_hardware)`
+
+Set `is_hardware` to true for HARDWARE method of rebooting.
+
+Set `is_hardware` to false for SOFTWARE method of rebooting.
+
+**Shutdown a server:**
+
+`server, err := api.ShutdownServer(server_id, is_hardware)`
+
+Set `is_hardware` to true for HARDWARE method of powering off.
+
+Set `is_hardware` to false for SOFTWARE method of powering off.
+
+**Assign a private network to a server:**
+
+`server, err := api.AssignServerPrivateNetwork(server_id, pn_id)`
+
+**Remove a server's private network:**
+
+`server, err := api.RemoveServerPrivateNetwork(server_id, pn_id)`
+
+**Create a new server's snapshot:**
+
+`server, err := api.CreateServerSnapshot(server_id)`
+
+**Restore a server's snapshot:**
+
+`server, err := api.RestoreServerSnapshot(server_id, snapshot_id)`
+
+**Remove a server's snapshot:**
+
+`server, err := api.DeleteServerSnapshot(server_id, snapshot_id);`
+
+**Clone a server:**
+
+`server, err := api.CloneServer(server_id, new_name)`
+
+
+### Images
+
+**List all images:**
+
+`images, err = api.ListImages()`
+
+Alternatively, use the method with query parameters.
+
+`images, err = api.ListImages(page, per_page, sort, query, fields)`
+
+To paginate the list of images received in the response use `page` and `per_page` parameters. set `per_page` to the number of images that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of images sorted in expected order pass an image property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the elements that contain it.
+
+To retrieve a collection of images containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,creation_date"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve a single image:**
+
+`image, err = api.GetImage(image_id)`
+
+
+**Create an image:**
+
+```
+request := oneandone.ImageConfig {
+ Name: image_name,
+ Description: image_description,
+ ServerId: server_id,
+ Frequency: image_frequenct,
+ NumImages: number_of_images,
+ }
+
+image_id, image, err = api.CreateImage(&request)
+```
+All fields except `Description` are required. `Frequency` may be set to `"ONCE"`, `"DAILY"` or `"WEEKLY"`.
+
+**Update an image:**
+
+
+`image, err = api.UpdateImage(image_id, new_name, new_description, new_frequenct)`
+
+If any of the parameters `new_name`, `new_description` or `new_frequenct` is set to an empty string, it is ignored in the request. `Frequency` may be set to `"ONCE"`, `"DAILY"` or `"WEEKLY"`.
+
+**Delete an image:**
+
+`image, err = api.DeleteImage(image_id)`
+
+### Shared Storages
+
+`ss, err := api.ListSharedStorages()`
+
+Alternatively, use the method with query parameters.
+
+`ss, err := api.ListSharedStorages(page, per_page, sort, query, fields)`
+
+To paginate the list of shared storages received in the response use `page` and `per_page` parameters. Set `per_page` to the number of volumes that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of shared storages sorted in expected order pass a volume property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the volume instances that contain it.
+
+To retrieve a collection of shared storages containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,size,size_used"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve a shared storage:**
+
+`ss, err := api.GetSharedStorage(ss_id)`
+
+
+**Create a shared storage:**
+
+```
+request := oneandone.SharedStorageRequest {
+ Name: test_ss_name,
+ Description: test_ss_desc,
+ Size: oneandone.Int2Pointer(size),
+ }
+
+ss_id, ss, err := api.CreateSharedStorage(&request)
+
+```
+`Description` is optional parameter.
+
+
+**Update a shared storage:**
+
+```
+request := oneandone.SharedStorageRequest {
+ Name: new_name,
+ Description: new_desc,
+ Size: oneandone.Int2Pointer(new_size),
+ }
+
+ss, err := api.UpdateSharedStorage(ss_id, &request)
+```
+All request's parameters are optional.
+
+
+**Remove a shared storage:**
+
+`ss, err := api.DeleteSharedStorage(ss_id)`
+
+
+**List a shared storage servers:**
+
+`ss_servers, err := api.ListSharedStorageServers(ss_id)`
+
+
+**Retrieve a shared storage server:**
+
+`ss_server, err := api.GetSharedStorageServer(ss_id, server_id)`
+
+
+**Add servers to a shared storage:**
+
+```
+servers := []oneandone.SharedStorageServer {
+ {
+ Id: server_id,
+ Rights: permissions,
+ } ,
+ }
+
+ss, err := api.AddSharedStorageServers(ss_id, servers)
+```
+`Rights` may be set to `R` or `RW` string.
+
+
+**Remove a server from a shared storage:**
+
+`ss, err := api.DeleteSharedStorageServer(ss_id, server_id)`
+
+
+**Retrieve the credentials for accessing the shared storages:**
+
+`ss_credentials, err := api.GetSharedStorageCredentials()`
+
+
+**Change the password for accessing the shared storages:**
+
+`ss_credentials, err := api.UpdateSharedStorageCredentials(new_password)`
+
+
+### Firewall Policies
+
+**List firewall policies:**
+
+`firewalls, err := api.ListFirewallPolicies()`
+
+Alternatively, use the method with query parameters.
+
+`firewalls, err := api.ListFirewallPolicies(page, per_page, sort, query, fields)`
+
+To paginate the list of firewall policies received in the response use `page` and `per_page` parameters. Set `per_page` to the number of firewall policies that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of firewall policies sorted in expected order pass a firewall policy property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the firewall policy instances that contain it.
+
+To retrieve a collection of firewall policies containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,creation_date"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve a single firewall policy:**
+
+`firewall, err := api.GetFirewallPolicy(fp_id)`
+
+
+**Create a firewall policy:**
+
+```
+request := oneandone.FirewallPolicyRequest {
+ Name: fp_name,
+ Description: fp_desc,
+ Rules: []oneandone.FirewallPolicyRule {
+ {
+ Protocol: protocol,
+ PortFrom: oneandone.Int2Pointer(port_from),
+ PortTo: oneandone.Int2Pointer(port_to),
+ SourceIp: source_ip,
+ },
+ },
+ }
+
+firewall_id, firewall, err := api.CreateFirewallPolicy(&request)
+```
+`SourceIp` and `Description` are optional parameters.
+
+
+**Update a firewall policy:**
+
+`firewall, err := api.UpdateFirewallPolicy(fp_id, fp_new_name, fp_new_description)`
+
+Passing an empty string in `fp_new_name` or `fp_new_description` skips updating the firewall policy name or description respectively.
+
+
+**Delete a firewall policy:**
+
+`firewall, err := api.DeleteFirewallPolicy(fp_id)`
+
+
+**List servers/IPs attached to a firewall policy:**
+
+`server_ips, err := api.ListFirewallPolicyServerIps(fp_id)`
+
+
+**Retrieve information about a server/IP assigned to a firewall policy:**
+
+`server_ip, err := api.GetFirewallPolicyServerIp(fp_id, ip_id)`
+
+
+**Add servers/IPs to a firewall policy:**
+
+`firewall, err := api.AddFirewallPolicyServerIps(fp_id, ip_ids)`
+
+`ip_ids` is a slice of IP ID's.
+
+
+**Remove a server/IP from a firewall policy:**
+
+`firewall, err := api.DeleteFirewallPolicyServerIp(fp_id, ip_id)`
+
+
+**List rules of a firewall policy:**
+
+`fp_rules, err := api.ListFirewallPolicyRules(fp_id)`
+
+
+**Retrieve information about a rule of a firewall policy:**
+
+`fp_rule, err := api.GetFirewallPolicyRule(fp_id, rule_id)`
+
+
+**Adds new rules to a firewall policy:**
+
+```
+fp_rules := []oneandone.FirewallPolicyRule {
+ {
+ Protocol: protocol1,
+ PortFrom: oneandone.Int2Pointer(port_from1),
+ PortTo: oneandone.Int2Pointer(port_to1),
+ SourceIp: source_ip,
+ },
+ {
+ Protocol: protocol2,
+ PortFrom: oneandone.Int2Pointer(port_from2),
+ PortTo: oneandone.Int2Pointer(port_to2),
+ },
+ }
+
+firewall, err := api.AddFirewallPolicyRules(fp_id, fp_rules)
+```
+
+**Remove a rule from a firewall policy:**
+
+`firewall, err := api.DeleteFirewallPolicyRule(fp_id, rule_id)`
+
+
+### Load Balancers
+
+**List load balancers:**
+
+`loadbalancers, err := api.ListLoadBalancers()`
+
+Alternatively, use the method with query parameters.
+
+`loadbalancers, err := api.ListLoadBalancers(page, per_page, sort, query, fields)`
+
+To paginate the list of load balancers received in the response use `page` and `per_page` parameters. Set `per_page` to the number of load balancers that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of load balancers sorted in expected order pass a load balancer property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the load balancer instances that contain it.
+
+To retrieve a collection of load balancers containing only the requested fields pass a list of comma separated properties (e.g. `"ip,name,method"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve a single load balancer:**
+
+`loadbalancer, err := api.GetLoadBalancer(lb_id)`
+
+
+**Create a load balancer:**
+
+```
+request := oneandone.LoadBalancerRequest {
+ Name: lb_name,
+ Description: lb_description,
+ Method: lb_method,
+ Persistence: oneandone.Bool2Pointer(true_or_false),
+ PersistenceTime: oneandone.Int2Pointer(seconds1),
+ HealthCheckTest: protocol1,
+ HealthCheckInterval: oneandone.Int2Pointer(seconds2),
+ HealthCheckPath: health_check_path,
+ HealthCheckPathParser: health_check_path_parser,
+ Rules: []oneandone.LoadBalancerRule {
+ {
+ Protocol: protocol1,
+ PortBalancer: lb_port,
+ PortServer: server_port,
+ Source: source_ip,
+ },
+ },
+ }
+
+loadbalancer_id, loadbalancer, err := api.CreateLoadBalancer(&request)
+```
+Optional parameters are `HealthCheckPath`, `HealthCheckPathParser`, `Source` and `Description`. Load balancer `Method` must be set to `"ROUND_ROBIN"` or `"LEAST_CONNECTIONS"`.
+
+**Update a load balancer:**
+```
+request := oneandone.LoadBalancerRequest {
+ Name: new_name,
+ Description: new_description,
+ Persistence: oneandone.Bool2Pointer(true_or_false),
+ PersistenceTime: oneandone.Int2Pointer(new_seconds1),
+ HealthCheckTest: new_protocol,
+ HealthCheckInterval: oneandone.Int2Pointer(new_seconds2),
+ HealthCheckPath: new_path,
+ HealthCheckPathParser: new_parser,
+ Method: new_lb_method,
+ }
+
+loadbalancer, err := api.UpdateLoadBalancer(lb_id, &request)
+```
+All updatable fields are optional.
+
+
+**Delete a load balancer:**
+
+`loadbalancer, err := api.DeleteLoadBalancer(lb_id)`
+
+
+**List servers/IPs attached to a load balancer:**
+
+`server_ips, err := api.ListLoadBalancerServerIps(lb_id)`
+
+
+**Retrieve information about a server/IP assigned to a load balancer:**
+
+`server_ip, err := api.GetLoadBalancerServerIp(lb_id, ip_id)`
+
+
+**Add servers/IPs to a load balancer:**
+
+`loadbalancer, err := api.AddLoadBalancerServerIps(lb_id, ip_ids)`
+
+`ip_ids` is a slice of IP ID's.
+
+
+**Remove a server/IP from a load balancer:**
+
+`loadbalancer, err := api.DeleteLoadBalancerServerIp(lb_id, ip_id)`
+
+
+**List rules of a load balancer:**
+
+`lb_rules, err := api.ListLoadBalancerRules(lb_id)`
+
+
+**Retrieve information about a rule of a load balancer:**
+
+`lb_rule, err := api.GetLoadBalancerRule(lb_id, rule_id)`
+
+
+**Adds new rules to a load balancer:**
+
+```
+lb_rules := []oneandone.LoadBalancerRule {
+ {
+ Protocol: protocol1,
+ PortBalancer: lb_port1,
+ PortServer: server_port1,
+ Source: source_ip,
+ },
+ {
+ Protocol: protocol2,
+ PortBalancer: lb_port2,
+ PortServer: server_port2,
+ },
+ }
+
+loadbalancer, err := api.AddLoadBalancerRules(lb_id, lb_rules)
+```
+
+**Remove a rule from a load balancer:**
+
+`loadbalancer, err := api.DeleteLoadBalancerRule(lb_id, rule_id)`
+
+
+### Public IPs
+
+**Retrieve a list of your public IPs:**
+
+`public_ips, err := api.ListPublicIps()`
+
+Alternatively, use the method with query parameters.
+
+`public_ips, err := api.ListPublicIps(page, per_page, sort, query, fields)`
+
+To paginate the list of public IPs received in the response use `page` and `per_page` parameters. Set `per_page` to the number of public IPs that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of public IPs sorted in expected order pass a public IP property (e.g. `"ip"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the public IP instances that contain it.
+
+To retrieve a collection of public IPs containing only the requested fields pass a list of comma separated properties (e.g. `"id,ip,reverse_dns"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+
+**Retrieve a single public IP:**
+
+`public_ip, err := api.GetPublicIp(ip_id)`
+
+
+**Create a public IP:**
+
+`ip_id, public_ip, err := api.CreatePublicIp(ip_type, reverse_dns)`
+
+Both parameters are optional and may be left blank. `ip_type` may be set to `"IPV4"` or `"IPV6"`. Presently, only IPV4 is supported.
+
+**Update the reverse DNS of a public IP:**
+
+`public_ip, err := api.UpdatePublicIp(ip_id, reverse_dns)`
+
+If an empty string is passed in `reverse_dns,` it removes previous reverse dns of the public IP.
+
+**Remove a public IP:**
+
+`public_ip, err := api.DeletePublicIp(ip_id)`
+
+
+### Private Networks
+
+**List all private networks:**
+
+`private_nets, err := api.ListPrivateNetworks()`
+
+Alternatively, use the method with query parameters.
+
+`private_nets, err := api.ListPrivateNetworks(page, per_page, sort, query, fields)`
+
+To paginate the list of private networks received in the response use `page` and `per_page` parameters. Set `per_page` to the number of private networks that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of private networks sorted in expected order pass a private network property (e.g. `"-creation_date"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the private network instances that contain it.
+
+To retrieve a collection of private networks containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,creation_date"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is blank, it is ignored in the request.
+
+**Retrieve information about a private network:**
+
+`private_net, err := api.GetPrivateNetwork(pn_id)`
+
+**Create a new private network:**
+
+```
+request := oneandone.PrivateNetworkRequest {
+ Name: pn_name,
+ Description: pn_description,
+ NetworkAddress: network_address,
+ SubnetMask: subnet_mask,
+ }
+
+pnet_id, private_net, err := api.CreatePrivateNetwork(&request)
+```
+Private network `Name` is required parameter.
+
+
+**Modify a private network:**
+
+```
+request := oneandone.PrivateNetworkRequest {
+ Name: new_pn_name,
+ Description: new_pn_description,
+ NetworkAddress: new_network_address,
+ SubnetMask: new_subnet_mask,
+ }
+
+private_net, err := api.UpdatePrivateNetwork(pn_id, &request)
+```
+All parameters in the request are optional.
+
+
+**Delete a private network:**
+
+`private_net, err := api.DeletePrivateNetwork(pn_id)`
+
+
+**List all servers attached to a private network:**
+
+`servers, err = := api.ListPrivateNetworkServers(pn_id)`
+
+
+**Retrieve a server attached to a private network:**
+
+`server, err = := api.GetPrivateNetworkServer(pn_id, server_id)`
+
+
+**Attach servers to a private network:**
+
+`private_net, err := api.AttachPrivateNetworkServers(pn_id, server_ids)`
+
+`server_ids` is a slice of server ID's.
+
+*Note:* Servers cannot be attached to a private network if they currently have a snapshot.
+
+
+**Remove a server from a private network:**
+
+`private_net, err := api.DetachPrivateNetworkServer(pn_id, server_id)`
+
+*Note:* The server cannot be removed from a private network if it currently has a snapshot or it is powered on.
+
+
+### VPNs
+
+**List all VPNs:**
+
+`vpns, err := api.ListVPNs()`
+
+Alternatively, use the method with query parameters.
+
+`vpns, err := api.ListVPNs(page, per_page, sort, query, fields)`
+
+To paginate the list of VPNs received in the response use `page` and `per_page` parameters. Set ` per_page` to the number of VPNs that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of VPNs sorted in expected order pass a VPN property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the VPN instances that contain it.
+
+To retrieve a collection of VPNs containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,creation_date"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve information about a VPN:**
+
+`vpn, err := api.GetVPN(vpn_id)`
+
+**Create a VPN:**
+
+`vpn, err := api.CreateVPN(vpn_name, vpn_description, datacenter_id)`
+
+**Modify a VPN:**
+
+`vpn, err := api.ModifyVPN(vpn_id, new_name, new_description)`
+
+**Delete a VPN:**
+
+`vpn, err := api.DeleteVPN(vpn_id)`
+
+**Retrieve a VPN's configuration file:**
+
+`base64_encoded_string, err := api.GetVPNConfigFile(vpn_id)`
+
+
+### Monitoring Center
+
+**List all usages and alerts of monitoring servers:**
+
+`server_usages, err := api.ListMonitoringServersUsages()`
+
+Alternatively, use the method with query parameters.
+
+`server_usages, err := api.ListMonitoringServersUsages(page, per_page, sort, query, fields)`
+
+To paginate the list of server usages received in the response use `page` and `per_page` parameters. Set `per_page` to the number of server usages that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of server usages sorted in expected order pass a server usage property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the usage instances that contain it.
+
+To retrieve a collection of server usages containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,status.state"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is blank, it is ignored in the request.
+
+**Retrieve the usages and alerts for a monitoring server:**
+
+`server_usage, err := api.GetMonitoringServerUsage(server_id, period)`
+
+`period` may be set to `"LAST_HOUR"`, `"LAST_24H"`, `"LAST_7D"`, `"LAST_30D"`, `"LAST_365D"` or `"CUSTOM"`. If `period` is set to `"CUSTOM"`, the `start_date` and `end_date` parameters are required to be set in **RFC 3339** date/time format (e.g. `2015-13-12T00:01:00Z`).
+
+`server_usage, err := api.GetMonitoringServerUsage(server_id, period, start_date, end_date)`
+
+### Monitoring Policies
+
+**List all monitoring policies:**
+
+`mon_policies, err := api.ListMonitoringPolicies()`
+
+Alternatively, use the method with query parameters.
+
+`mon_policies, err := api.ListMonitoringPolicies(page, per_page, sort, query, fields)`
+
+To paginate the list of monitoring policies received in the response use `page` and `per_page` parameters. Set `per_page` to the number of monitoring policies that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of monitoring policies sorted in expected order pass a monitoring policy property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the monitoring policy instances that contain it.
+
+To retrieve a collection of monitoring policies containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,creation_date"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve a single monitoring policy:**
+
+`mon_policy, err := api.GetMonitoringPolicy(mp_id)`
+
+
+**Create a monitoring policy:**
+
+```
+request := oneandone.MonitoringPolicy {
+ Name: mp_name,
+ Description: mp_desc,
+ Email: mp_mail,
+ Agent: true_or_false,
+ Thresholds: &oneandone.MonitoringThreshold {
+ Cpu: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ Ram: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ Disk: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ Transfer: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ InternalPing: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ },
+ Ports: []oneandone.MonitoringPort {
+ {
+ Protocol: protocol,
+ Port: port,
+ AlertIf: responding_or_not_responding,
+ EmailNotification: true_or_false,
+ },
+ },
+ Processes: []oneandone.MonitoringProcess {
+ {
+ Process: process_name,
+ AlertIf: running_or_not_running,
+ EmailNotification: true_or_false,
+ },
+ },
+ }
+
+mpolicy_id, mon_policy, err := api.CreateMonitoringPolicy(&request)
+```
+All fields, except `Description`, are required. `AlertIf` property accepts values `"RESPONDING"`/`"NOT_RESPONDING"` for ports, and `"RUNNING"`/`"NOT_RUNNING"` for processes.
+
+
+**Update a monitoring policy:**
+
+```
+request := oneandone.MonitoringPolicy {
+ Name: new_mp_name,
+ Description: new_mp_desc,
+ Email: new_mp_mail,
+ Thresholds: &oneandone.MonitoringThreshold {
+ Cpu: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ Ram: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ Disk: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ Transfer: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ InternalPing: &oneandone.MonitoringLevel {
+ Warning: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ Critical: &oneandone.MonitoringValue {
+ Value: new_threshold_value,
+ Alert: true_or_false,
+ },
+ },
+ },
+ }
+
+mon_policy, err := api.UpdateMonitoringPolicy(mp_id, &request)
+```
+All fields of the request are optional. When a threshold is specified in the request, the threshold fields are required.
+
+**Delete a monitoring policy:**
+
+`mon_policy, err := api.DeleteMonitoringPolicy(mp_id)`
+
+
+**List all ports of a monitoring policy:**
+
+`mp_ports, err := api.ListMonitoringPolicyPorts(mp_id)`
+
+
+**Retrieve information about a port of a monitoring policy:**
+
+`mp_port, err := api.GetMonitoringPolicyPort(mp_id, port_id)`
+
+
+**Add new ports to a monitoring policy:**
+
+```
+mp_ports := []oneandone.MonitoringPort {
+ {
+ Protocol: protocol1,
+ Port: port1,
+ AlertIf: responding_or_not_responding,
+ EmailNotification: true_or_false,
+ },
+ {
+ Protocol: protocol2,
+ Port: port2,
+ AlertIf: responding_or_not_responding,
+ EmailNotification: true_or_false,
+ },
+ }
+
+mon_policy, err := api.AddMonitoringPolicyPorts(mp_id, mp_ports)
+```
+Port properties are mandatory.
+
+
+**Modify a port of a monitoring policy:**
+
+```
+mp_port := oneandone.MonitoringPort {
+ Protocol: protocol,
+ Port: port,
+ AlertIf: responding_or_not_responding,
+ EmailNotification: true_or_false,
+ }
+
+mon_policy, err := api.ModifyMonitoringPolicyPort(mp_id, port_id, &mp_port)
+```
+*Note:* `Protocol` and `Port` cannot be changed.
+
+
+**Remove a port from a monitoring policy:**
+
+`mon_policy, err := api.DeleteMonitoringPolicyPort(mp_id, port_id)`
+
+
+**List the processes of a monitoring policy:**
+
+`mp_processes, err := api.ListMonitoringPolicyProcesses(mp_id)`
+
+
+**Retrieve information about a process of a monitoring policy:**
+
+`mp_process, err := api.GetMonitoringPolicyProcess(mp_id, process_id)`
+
+
+**Add new processes to a monitoring policy:**
+
+```
+processes := []oneandone.MonitoringProcess {
+ {
+ Process: process_name1,
+ AlertIf: running_or_not_running,
+ EmailNotification: true_or_false,
+ },
+ {
+ Process: process_name2,
+ AlertIf: running_or_not_running,
+ EmailNotification: true_or_false,
+ },
+ }
+
+mon_policy, err := api.AddMonitoringPolicyProcesses(mp_id, processes)
+```
+All properties of the `MonitoringProcess` instance are required.
+
+
+**Modify a process of a monitoring policy:**
+
+```
+process := oneandone.MonitoringProcess {
+ Process: process_name,
+ AlertIf: running_or_not_running,
+ EmailNotification: true_or_false,
+ }
+
+mon_policy, err := api.ModifyMonitoringPolicyProcess(mp_id, process_id, &process)
+```
+
+*Note:* Process name cannot be changed.
+
+**Remove a process from a monitoring policy:**
+
+`mon_policy, err := api.DeleteMonitoringPolicyProcess(mp_id, process_id)`
+
+**List all servers attached to a monitoring policy:**
+
+`mp_servers, err := api.ListMonitoringPolicyServers(mp_id)`
+
+**Retrieve information about a server attached to a monitoring policy:**
+
+`mp_server, err := api.GetMonitoringPolicyServer(mp_id, server_id)`
+
+**Attach servers to a monitoring policy:**
+
+`mon_policy, err := api.AttachMonitoringPolicyServers(mp_id, server_ids)`
+
+`server_ids` is a slice of server ID's.
+
+**Remove a server from a monitoring policy:**
+
+`mon_policy, err := api.RemoveMonitoringPolicyServer(mp_id, server_id)`
+
+
+### Logs
+
+**List all logs:**
+
+`logs, err := api.ListLogs(period, nil, nil)`
+
+`period` can be set to `"LAST_HOUR"`, `"LAST_24H"`, `"LAST_7D"`, `"LAST_30D"`, `"LAST_365D"` or `"CUSTOM"`. If `period` is set to `"CUSTOM"`, the `start_date` and `end_date` parameters are required to be set in **RFC 3339** date/time format (e.g. `2015-13-12T00:01:00Z`).
+
+`logs, err := api.ListLogs(period, start_date, end_date)`
+
+Additional query parameters can be used.
+
+`logs, err := api.ListLogs(period, start_date, end_date, page, per_page, sort, query, fields)`
+
+To paginate the list of logs received in the response use `page` and `per_page` parameters. Set ` per_page` to the number of logs that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of logs sorted in expected order pass a logs property (e.g. `"action"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the logs instances that contain it.
+
+To retrieve a collection of logs containing only the requested fields pass a list of comma separated properties (e.g. `"id,action,type"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve a single log:**
+
+`log, err := api.GetLog(log_id)`
+
+
+### Users
+
+**List all users:**
+
+`users, err := api.ListUsers()`
+
+Alternatively, use the method with query parameters.
+
+`users, err := api.ListUsers(page, per_page, sort, query, fields)`
+
+To paginate the list of users received in the response use `page` and `per_page` parameters. Set ` per_page` to the number of users that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of users sorted in expected order pass a user property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the user instances that contain it.
+
+To retrieve a collection of users containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,creation_date,email"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve information about a user:**
+
+`user, err := api.GetUser(user_id)`
+
+**Create a user:**
+
+```
+request := oneandone.UserRequest {
+ Name: username,
+ Description: user_description,
+ Password: password,
+ Email: user_email,
+ }
+
+user_id, user, err := api.CreateUser(&request)
+```
+
+`Name` and `Password` are required parameters. The password must contain at least 8 characters using uppercase letters, numbers and other special symbols.
+
+**Modify a user:**
+
+```
+request := oneandone.UserRequest {
+ Description: new_desc,
+ Email: new_mail,
+ Password: new_pass,
+ State: state,
+ }
+
+user, err := api.ModifyUser(user_id, &request)
+```
+
+All listed fields in the request are optional. `State` can be set to `"ACTIVE"` or `"DISABLED"`.
+
+**Delete a user:**
+
+`user, err := api.DeleteUser(user_id)`
+
+**Retrieve information about a user's API privileges:**
+
+`api_info, err := api.GetUserApi(user_id)`
+
+**Retrieve a user's API key:**
+
+`api_key, err := api.GetUserApiKey(user_id)`
+
+**List IP's from which API access is allowed for a user:**
+
+`allowed_ips, err := api.ListUserApiAllowedIps(user_id)`
+
+**Add new IP's to a user:**
+
+```
+user_ips := []string{ my_public_ip, "192.168.7.77", "10.81.12.101" }
+user, err := api.AddUserApiAlowedIps(user_id, user_ips)
+```
+
+**Remove an IP and forbid API access from it:**
+
+`user, err := api.RemoveUserApiAllowedIp(user_id, ip)`
+
+**Modify a user's API privileges:**
+
+`user, err := api.ModifyUserApi(user_id, is_active)`
+
+**Renew a user's API key:**
+
+`user, err := api.RenewUserApiKey(user_id)`
+
+**Retrieve current user permissions:**
+
+`permissions, err := api.GetCurrentUserPermissions()`
+
+
+### Roles
+
+**List all roles:**
+
+`roles, err := api.ListRoles()`
+
+Alternatively, use the method with query parameters.
+
+`roles, err := api.ListRoles(page, per_page, sort, query, fields)`
+
+To paginate the list of roles received in the response use `page` and `per_page` parameters. Set ` per_page` to the number of roles that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of roles sorted in expected order pass a role property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the role instances that contain it.
+
+To retrieve a collection of roles containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,creation_date"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+**Retrieve information about a role:**
+
+`role, err := api.GetRole(role_id)`
+
+**Create a role:**
+
+`role, err := api.CreateRole(role_name)`
+
+**Clone a role:**
+
+`role, err := api.CloneRole(role_id, new_role_name)`
+
+**Modify a role:**
+
+`role, err := api.ModifyRole(role_id, new_name, new_description, new_state)`
+
+`ACTIVE` and `DISABLE` are valid values for the state.
+
+**Delete a role:**
+
+`role, err := api.DeleteRole(role_id)`
+
+**Retrieve information about a role's permissions:**
+
+`permissions, err := api.GetRolePermissions(role_id)`
+
+**Modify a role's permissions:**
+
+`role, err := api.ModifyRolePermissions(role_id, permissions)`
+
+**Assign users to a role:**
+
+`role, err := api.AssignRoleUsers(role_id, user_ids)`
+
+`user_ids` is a slice of user ID's.
+
+**List a role's users:**
+
+`users, err := api.ListRoleUsers(role_id)`
+
+**Retrieve information about a role's user:**
+
+`user, err := api.GetRoleUser(role_id, user_id)`
+
+**Remove a role's user:**
+
+`role, err := api.RemoveRoleUser(role_id, user_id)`
+
+
+### Usages
+
+**List your usages:**
+
+`usages, err := api.ListUsages(period, nil, nil)`
+
+`period` can be set to `"LAST_HOUR"`, `"LAST_24H"`, `"LAST_7D"`, `"LAST_30D"`, `"LAST_365D"` or `"CUSTOM"`. If `period` is set to `"CUSTOM"`, the `start_date` and `end_date` parameters are required to be set in **RFC 3339** date/time format (e.g. `2015-13-12T00:01:00Z`).
+
+`usages, err := api.ListUsages(period, start_date, end_date)`
+
+Additional query parameters can be used.
+
+`usages, err := api.ListUsages(period, start_date, end_date, page, per_page, sort, query, fields)`
+
+To paginate the list of usages received in the response use `page` and `per_page` parameters. Set ` per_page` to the number of usages that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of usages sorted in expected order pass a usages property (e.g. `"name"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the usages instances that contain it.
+
+To retrieve a collection of usages containing only the requested fields pass a list of comma separated properties (e.g. `"id,name"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is set to an empty string, it is ignored in the request.
+
+
+### Server Appliances
+
+**List all the appliances that you can use to create a server:**
+
+`server_appliances, err := api.ListServerAppliances()`
+
+Alternatively, use the method with query parameters.
+
+`server_appliances, err := api.ListServerAppliances(page, per_page, sort, query, fields)`
+
+To paginate the list of server appliances received in the response use `page` and `per_page` parameters. Set `per_page` to the number of server appliances that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of server appliances sorted in expected order pass a server appliance property (e.g. `"os"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the server appliance instances that contain it.
+
+To retrieve a collection of server appliances containing only the requested fields pass a list of comma separated properties (e.g. `"id,os,architecture"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is blank, it is ignored in the request.
+
+**Retrieve information about specific appliance:**
+
+`server_appliance, err := api.GetServerAppliance(appliance_id)`
+
+
+### DVD ISO
+
+**List all operative systems and tools that you can load into your virtual DVD unit:**
+
+`dvd_isos, err := api.ListDvdIsos()`
+
+Alternatively, use the method with query parameters.
+
+`dvd_isos, err := api.ListDvdIsos(page, per_page, sort, query, fields)`
+
+To paginate the list of ISO DVDs received in the response use `page` and `per_page` parameters. Set `per_page` to the number of ISO DVDs that will be shown in each page. `page` indicates the current page. When set to an integer value that is less or equal to zero, the parameters are ignored by the framework.
+
+To receive the list of ISO DVDs sorted in expected order pass a ISO DVD property (e.g. `"type"`) in `sort` parameter. Prefix the sorting attribute with `-` sign for sorting in descending order.
+
+Use `query` parameter to search for a string in the response and return only the ISO DVD instances that contain it.
+
+To retrieve a collection of ISO DVDs containing only the requested fields pass a list of comma separated properties (e.g. `"id,name,type"`) in `fields` parameter.
+
+If any of the parameters `sort`, `query` or `fields` is blank, it is ignored in the request.
+
+**Retrieve a specific ISO image:**
+
+`dvd_iso, err := api.GetDvdIso(dvd_id)`
+
+
+### Ping
+
+**Check if 1&1 REST API is running:**
+
+`response, err := api.Ping()`
+
+If the API is running, the response is a single-element slice `["PONG"]`.
+
+**Validate if 1&1 REST API is running and the authorization token is valid:**
+
+`response, err := api.PingAuth()`
+
+The response should be a single-element slice `["PONG"]` if the API is running and the token is valid.
+
+
+### Pricing
+
+**Show prices for all available resources in the Cloud Panel:**
+
+`pricing, err := api.GetPricing()`
+
+
+### Data Centers
+
+**List all 1&1 Cloud Server data centers:**
+
+`datacenters, err := api.ListDatacenters()`
+
+Here is another example of an alternative form of the list function that includes query parameters.
+
+`datacenters, err := api.ListDatacenters(0, 0, "country_code", "DE", "id,country_code")`
+
+**Retrieve a specific data center:**
+
+`datacenter, err := api.GetDatacenter(datacenter_id)`
+
+
+## Examples
+
+```Go
+package main
+
+import (
+ "fmt"
+ "github.com/1and1/oneandone-cloudserver-sdk-go"
+ "time"
+)
+
+func main() {
+ //Set an authentication token
+ token := oneandone.SetToken("82ee732b8d47e451be5c6ad5b7b56c81")
+ //Create an API client
+ api := oneandone.New(token, oneandone.BaseUrl)
+
+ // List server appliances
+ saps, err := api.ListServerAppliances()
+
+ var sa oneandone.ServerAppliance
+ for _, a := range saps {
+ if a.Type == "IMAGE" {
+ sa = a
+ }
+ }
+
+ // Create a server
+ req := oneandone.ServerRequest{
+ Name: "Example Server",
+ Description: "Example server description.",
+ ApplianceId: sa.Id,
+ PowerOn: true,
+ Hardware: oneandone.Hardware{
+ Vcores: 1,
+ CoresPerProcessor: 1,
+ Ram: 2,
+ Hdds: []oneandone.Hdd {
+ oneandone.Hdd {
+ Size: sa.MinHddSize,
+ IsMain: true,
+ },
+ },
+ },
+ }
+
+ server_id, server, err := api.CreateServer(&req)
+
+ if err == nil {
+ // Wait until server is created and powered on for at most 60 x 10 seconds
+ err = api.WaitForState(server, "POWERED_ON", 10, 60)
+ }
+
+ // Get the server
+ server, err = api.GetServer(server_id)
+
+ // Create a load balancer
+ lbr := oneandone.LoadBalancerRequest {
+ Name: "Load Balancer Example",
+ Description: "API created load balancer.",
+ Method: "ROUND_ROBIN",
+ Persistence: oneandone.Bool2Pointer(true),
+ PersistenceTime: oneandone.Int2Pointer(1200),
+ HealthCheckTest: "TCP",
+ HealthCheckInterval: oneandone.Int2Pointer(40),
+ Rules: []oneandone.LoadBalancerRule {
+ {
+ Protocol: "TCP",
+ PortBalancer: 80,
+ PortServer: 80,
+ Source: "0.0.0.0",
+ },
+ },
+ }
+
+ var lb *oneandone.LoadBalancer
+ var lb_id string
+
+ lb_id, lb, err = api.CreateLoadBalancer(&lbr)
+ if err != nil {
+ api.WaitForState(lb, "ACTIVE", 10, 30)
+ }
+
+ // Get the load balancer
+ lb, err = api.GetLoadBalancer(lb.Id)
+
+ // Assign the load balancer to server's IP
+ server, err = api.AssignServerIpLoadBalancer(server.Id, server.Ips[0].Id, lb_id)
+
+ // Create a firewall policy
+ fpr := oneandone.FirewallPolicyRequest{
+ Name: "Firewall Policy Example",
+ Description: "API created firewall policy.",
+ Rules: []oneandone.FirewallPolicyRule {
+ {
+ Protocol: "TCP",
+ PortFrom: oneandone.Int2Pointer(80),
+ PortTo: oneandone.Int2Pointer(80),
+ },
+ },
+ }
+
+ var fp *oneandone.FirewallPolicy
+
+ fp_id, fp, err = api.CreateFirewallPolicy(&fpr)
+ if err == nil {
+ api.WaitForState(fp, "ACTIVE", 10, 30)
+ }
+
+ // Get the firewall policy
+ fp, err = api.GetFirewallPolicy(fp_id)
+
+ // Add servers IPs to the firewall policy.
+ ips := []string{ server.Ips[0].Id }
+
+ fp, err = api.AddFirewallPolicyServerIps(fp.Id, ips)
+ if err == nil {
+ api.WaitForState(fp, "ACTIVE", 10, 60)
+ }
+
+ //Shutdown the server using 'SOFTWARE' method
+ server, err = api.ShutdownServer(server.Id, false)
+ if err != nil {
+ err = api.WaitForState(server, "POWERED_OFF", 5, 20)
+ }
+
+ // Delete the load balancer
+ lb, err = api.DeleteLoadBalancer(lb.Id)
+ if err != nil {
+ err = api.WaitUntilDeleted(lb)
+ }
+
+ // Delete the firewall policy
+ fp, err = api.DeleteFirewallPolicy(fp.Id)
+ if err != nil {
+ err = api.WaitUntilDeleted(fp)
+ }
+
+ // List usages in last 24h
+ var usages *oneandone.Usages
+ usages, err = api.ListUsages("LAST_24H", nil, nil)
+
+ fmt.Println(usages.Servers)
+
+ // List usages in last 5 hours
+ n := time.Now()
+ ed := time.Date(n.Year(), n.Month(), n.Day(), n.Hour(), n.Minute(), n.Second(), 0, time.UTC)
+ sd := ed.Add(-(time.Hour * 5))
+
+ usages, err = api.ListUsages("CUSTOM", &sd, &ed)
+
+ //Create a shared storage
+ ssr := oneandone.SharedStorageRequest {
+ Name: "Shared Storage Example",
+ Description: "API alocated 100 GB disk.",
+ Size: oneandone.Int2Pointer(100),
+ }
+
+ var ss *oneandone.SharedStorage
+ var ss_id string
+
+ ss_id, ss, err = api.CreateSharedStorage(&ssr)
+ if err != nil {
+ api.WaitForState(ss, "ACTIVE", 10, 30)
+ }
+
+ // List shared storages on page 1, 5 results per page and sort by 'name' field.
+ // Include only 'name', 'size' and 'minimum_size_allowed' fields in the result.
+ var shs []oneandone.SharedStorage
+ shs, err = api.ListSharedStorages(1, 5, "name", "", "name,size,minimum_size_allowed")
+
+ // List all shared storages that contain 'example' string
+ shs, err = api.ListSharedStorages(0, 0, "", "example", "")
+
+ // Delete the shared storage
+ ss, err = api.DeleteSharedStorage(ss_id)
+ if err == nil {
+ err = api.WaitUntilDeleted(ss)
+ }
+
+ // Delete the server
+ server, err = api.DeleteServer(server.Id, false)
+ if err == nil {
+ err = api.WaitUntilDeleted(server)
+ }
+}
+
+```
+The next example illustrates how to create a `TYPO3` application server of a fixed size with an initial password and a firewall policy that has just been created.
+
+```Go
+package main
+
+import "github.com/1and1/oneandone-cloudserver-sdk-go"
+
+func main() {
+ token := oneandone.SetToken("bde36026df9d548f699ea97e75a7e87f")
+ client := oneandone.New(token, oneandone.BaseUrl)
+
+ // Create a new firewall policy
+ fpr := oneandone.FirewallPolicyRequest{
+ Name: "HTTPS Traffic Policy",
+ Rules: []oneandone.FirewallPolicyRule{
+ {
+ Protocol: "TCP",
+ PortFrom: oneandone.Int2Pointer(443),
+ PortTo: oneandone.Int2Pointer(443),
+ },
+ },
+ }
+
+ _, fp, err := client.CreateFirewallPolicy(&fpr)
+ if fp != nil && err == nil {
+ client.WaitForState(fp, "ACTIVE", 5, 60)
+
+ // Look for the TYPO3 application appliance
+ saps, _ := client.ListServerAppliances(0, 0, "", "typo3", "")
+
+ var sa oneandone.ServerAppliance
+ for _, a := range saps {
+ if a.Type == "APPLICATION" {
+ sa = a
+ break
+ }
+ }
+
+ var fixed_flavours []oneandone.FixedInstanceInfo
+ var fixed_size_id string
+
+ fixed_flavours, err = client.ListFixedInstanceSizes()
+ for _, fl := range fixed_flavours {
+ //look for 'M' size
+ if fl.Name == "M" {
+ fixed_size_id = fl.Id
+ break
+ }
+ }
+
+ req := oneandone.ServerRequest{
+ Name: "TYPO3 Server",
+ ApplianceId: sa.Id,
+ PowerOn: true,
+ Password: "ucr_kXW8,.2SdMU",
+ Hardware: oneandone.Hardware{
+ FixedInsSizeId: fixed_size_id,
+ },
+ FirewallPolicyId: fp.Id,
+ }
+ _, server, _ := client.CreateServer(&req)
+ if server != nil {
+ client.WaitForState(server, "POWERED_ON", 10, 90)
+ }
+ }
+}
+```
+
+
+## Index
+
+```Go
+func New(token string, url string) *API
+```
+
+```Go
+func (api *API) AddFirewallPolicyRules(fp_id string, fp_rules []FirewallPolicyRule) (*FirewallPolicy, error)
+```
+
+```Go
+func (api *API) AddFirewallPolicyServerIps(fp_id string, ip_ids []string) (*FirewallPolicy, error)
+```
+
+```Go
+func (api *API) AddLoadBalancerRules(lb_id string, lb_rules []LoadBalancerRule) (*LoadBalancer, error)
+```
+
+```Go
+func (api *API) AddLoadBalancerServerIps(lb_id string, ip_ids []string) (*LoadBalancer, error)
+```
+
+```Go
+func (api *API) AddMonitoringPolicyPorts(mp_id string, mp_ports []MonitoringPort) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) AddMonitoringPolicyProcesses(mp_id string, mp_procs []MonitoringProcess) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) AddServerHdds(server_id string, hdds *ServerHdds) (*Server, error)
+```
+
+```Go
+func (api *API) AddSharedStorageServers(st_id string, servers []SharedStorageServer) (*SharedStorage, error)
+```
+
+```Go
+func (api *API) AddUserApiAlowedIps(user_id string, ips []string) (*User, error)
+```
+
+```Go
+func (api *API) AssignRoleUsers(role_id string, user_ids []string) (*Role, error)
+```
+
+```Go
+func (api *API) AssignServerIp(server_id string, ip_type string) (*Server, error)
+```
+
+```Go
+func (api *API) AssignServerIpFirewallPolicy(server_id string, ip_id string, fp_id string) (*Server, error)
+```
+
+```Go
+func (api *API) AssignServerIpLoadBalancer(server_id string, ip_id string, lb_id string) (*Server, error)
+```
+
+```Go
+func (api *API) AssignServerPrivateNetwork(server_id string, pn_id string) (*Server, error)
+```
+
+```Go
+func (api *API) AttachMonitoringPolicyServers(mp_id string, sids []string) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) AttachPrivateNetworkServers(pn_id string, sids []string) (*PrivateNetwork, error)
+```
+
+```Go
+func (api *API) CloneRole(role_id string, name string) (*Role, error)
+```
+
+```Go
+func (api *API) CloneServer(server_id string, new_name string, datacenter_id string) (*Server, error)
+```
+
+```Go
+func (api *API) CreateFirewallPolicy(fp_data *FirewallPolicyRequest) (string, *FirewallPolicy, error)
+```
+
+```Go
+func (api *API) CreateImage(request *ImageConfig) (string, *Image, error)
+```
+
+```Go
+func (api *API) CreateLoadBalancer(request *LoadBalancerRequest) (string, *LoadBalancer, error)
+```
+
+```Go
+func (api *API) CreateMonitoringPolicy(mp *MonitoringPolicy) (string, *MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) CreatePrivateNetwork(request *PrivateNetworkRequest) (string, *PrivateNetwork, error)
+```
+
+```Go
+func (api *API) CreatePublicIp(ip_type string, reverse_dns string, datacenter_id string) (string, *PublicIp, error)
+```
+
+```Go
+func (api *API) CreateRole(name string) (string, *Role, error)
+```
+
+```Go
+func (api *API) CreateServer(request *ServerRequest) (string, *Server, error)
+```
+
+```Go
+func (api *API) CreateServerEx(request *ServerRequest, timeout int) (string, string, error)
+```
+
+```Go
+func (api *API) CreateServerSnapshot(server_id string) (*Server, error)
+```
+
+```Go
+func (api *API) CreateSharedStorage(request *SharedStorageRequest) (string, *SharedStorage, error)
+```
+
+```Go
+func (api *API) CreateUser(user *UserRequest) (string, *User, error)
+```
+
+```Go
+func (api *API) CreateVPN(name string, description string, datacenter_id string) (string, *VPN, error)
+```
+
+```Go
+func (api *API) DeleteFirewallPolicy(fp_id string) (*FirewallPolicy, error)
+```
+
+```Go
+func (api *API) DeleteFirewallPolicyRule(fp_id string, rule_id string) (*FirewallPolicy, error)
+```
+
+```Go
+func (api *API) DeleteFirewallPolicyServerIp(fp_id string, ip_id string) (*FirewallPolicy, error)
+```
+
+```Go
+func (api *API) DeleteImage(img_id string) (*Image, error)
+```
+
+```Go
+func (api *API) DeleteLoadBalancer(lb_id string) (*LoadBalancer, error)
+```
+
+```Go
+func (api *API) DeleteLoadBalancerRule(lb_id string, rule_id string) (*LoadBalancer, error)
+```
+
+```Go
+func (api *API) DeleteLoadBalancerServerIp(lb_id string, ip_id string) (*LoadBalancer, error)
+```
+
+```Go
+func (api *API) DeleteMonitoringPolicy(mp_id string) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) DeleteMonitoringPolicyPort(mp_id string, port_id string) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) DeleteMonitoringPolicyProcess(mp_id string, proc_id string) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) DeletePrivateNetwork(pn_id string) (*PrivateNetwork, error)
+```
+
+```Go
+func (api *API) DeletePublicIp(ip_id string) (*PublicIp, error)
+```
+
+```Go
+func (api *API) DeleteRole(role_id string) (*Role, error)
+```
+
+```Go
+func (api *API) DeleteServer(server_id string, keep_ips bool) (*Server, error)
+```
+
+```Go
+func (api *API) DeleteServerHdd(server_id string, hdd_id string) (*Server, error)
+```
+
+```Go
+func (api *API) DeleteServerIp(server_id string, ip_id string, keep_ip bool) (*Server, error)
+```
+
+```Go
+func (api *API) DeleteServerSnapshot(server_id string, snapshot_id string) (*Server, error)
+```
+
+```Go
+func (api *API) DeleteSharedStorage(ss_id string) (*SharedStorage, error)
+```
+
+```Go
+func (api *API) DeleteSharedStorageServer(st_id string, ser_id string) (*SharedStorage, error)
+```
+
+```Go
+func (api *API) DeleteUser(user_id string) (*User, error)
+```
+
+```Go
+func (api *API) DeleteVPN(vpn_id string) (*VPN, error)
+```
+
+```Go
+func (api *API) DetachPrivateNetworkServer(pn_id string, pns_id string) (*PrivateNetwork, error)
+```
+
+```Go
+func (api *API) EjectServerDvd(server_id string) (*Server, error)
+```
+
+```Go
+func (api *API) GetCurrentUserPermissions() (*Permissions, error)
+```
+
+```Go
+func (api *API) GetDatacenter(dc_id string) (*Datacenter, error)
+```
+
+```Go
+func (api *API) GetDvdIso(dvd_id string) (*DvdIso, error)
+```
+
+```Go
+func (api *API) GetFirewallPolicy(fp_id string) (*FirewallPolicy, error)
+```
+
+```Go
+func (api *API) GetFirewallPolicyRule(fp_id string, rule_id string) (*FirewallPolicyRule, error)
+```
+
+```Go
+func (api *API) GetFirewallPolicyServerIp(fp_id string, ip_id string) (*ServerIpInfo, error)
+```
+
+```Go
+func (api *API) GetFixedInstanceSize(fis_id string) (*FixedInstanceInfo, error)
+```
+
+```Go
+func (api *API) GetImage(img_id string) (*Image, error)
+```
+
+```Go
+func (api *API) GetLoadBalancer(lb_id string) (*LoadBalancer, error)
+```
+
+```Go
+func (api *API) GetLoadBalancerRule(lb_id string, rule_id string) (*LoadBalancerRule, error)
+```
+
+```Go
+func (api *API) GetLoadBalancerServerIp(lb_id string, ip_id string) (*ServerIpInfo, error)
+```
+
+```Go
+func (api *API) GetLog(log_id string) (*Log, error)
+```
+
+```Go
+func (api *API) GetMonitoringPolicy(mp_id string) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) GetMonitoringPolicyPort(mp_id string, port_id string) (*MonitoringPort, error)
+```
+
+```Go
+func (api *API) GetMonitoringPolicyProcess(mp_id string, proc_id string) (*MonitoringProcess, error)
+```
+
+```Go
+func (api *API) GetMonitoringPolicyServer(mp_id string, ser_id string) (*Identity, error)
+```
+
+```Go
+func (api *API) GetMonitoringServerUsage(ser_id string, period string, dates ...time.Time) (*MonServerUsageDetails, error)
+```
+
+```Go
+func (api *API) GetPricing() (*Pricing, error)
+```
+
+```Go
+func (api *API) GetPrivateNetwork(pn_id string) (*PrivateNetwork, error)
+```
+
+```Go
+func (api *API) GetPrivateNetworkServer(pn_id string, server_id string) (*Identity, error)
+```
+
+```Go
+func (api *API) GetPublicIp(ip_id string) (*PublicIp, error)
+```
+
+```Go
+func (api *API) GetRole(role_id string) (*Role, error)
+```
+
+```Go
+func (api *API) GetRolePermissions(role_id string) (*Permissions, error)
+```
+
+```Go
+func (api *API) GetRoleUser(role_id string, user_id string) (*Identity, error)
+```
+
+```Go
+func (api *API) GetServer(server_id string) (*Server, error)
+```
+
+```Go
+func (api *API) GetServerAppliance(sa_id string) (*ServerAppliance, error)
+```
+
+```Go
+func (api *API) GetServerDvd(server_id string) (*Identity, error)
+```
+
+```Go
+func (api *API) GetServerHardware(server_id string) (*Hardware, error)
+```
+
+```Go
+func (api *API) GetServerHdd(server_id string, hdd_id string) (*Hdd, error)
+```
+
+```Go
+func (api *API) GetServerImage(server_id string) (*Identity, error)
+```
+
+```Go
+func (api *API) GetServerIp(server_id string, ip_id string) (*ServerIp, error)
+```
+
+```Go
+func (api *API) GetServerIpFirewallPolicy(server_id string, ip_id string) (*Identity, error)
+```
+
+```Go
+func (api *API) GetServerPrivateNetwork(server_id string, pn_id string) (*PrivateNetwork, error)
+```
+
+```Go
+func (api *API) GetServerSnapshot(server_id string) (*ServerSnapshot, error)
+```
+
+```Go
+func (api *API) GetServerStatus(server_id string) (*Status, error)
+```
+
+```Go
+func (api *API) GetSharedStorage(ss_id string) (*SharedStorage, error)
+```
+
+```Go
+func (api *API) GetSharedStorageCredentials() ([]SharedStorageAccess, error)
+```
+
+```Go
+func (api *API) GetSharedStorageServer(st_id string, ser_id string) (*SharedStorageServer, error)
+```
+
+```Go
+func (api *API) GetUser(user_id string) (*User, error)
+```
+
+```Go
+func (api *API) GetUserApi(user_id string) (*UserApi, error)
+```
+
+```Go
+func (api *API) GetUserApiKey(user_id string) (*UserApiKey, error)
+```
+
+```Go
+func (api *API) GetVPN(vpn_id string) (*VPN, error)
+```
+
+```Go
+func (api *API) GetVPNConfigFile(vpn_id string) (string, error)
+```
+
+```Go
+func (api *API) ListDatacenters(args ...interface{}) ([]Datacenter, error)
+```
+
+```Go
+func (api *API) ListDvdIsos(args ...interface{}) ([]DvdIso, error)
+```
+
+```Go
+func (api *API) ListFirewallPolicies(args ...interface{}) ([]FirewallPolicy, error)
+```
+
+```Go
+func (api *API) ListFirewallPolicyRules(fp_id string) ([]FirewallPolicyRule, error)
+```
+
+```Go
+func (api *API) ListFirewallPolicyServerIps(fp_id string) ([]ServerIpInfo, error)
+```
+
+```Go
+func (api *API) ListFixedInstanceSizes() ([]FixedInstanceInfo, error)
+```
+
+```Go
+func (api *API) ListImages(args ...interface{}) ([]Image, error)
+```
+
+```Go
+func (api *API) ListLoadBalancerRules(lb_id string) ([]LoadBalancerRule, error)
+```
+
+```Go
+func (api *API) ListLoadBalancerServerIps(lb_id string) ([]ServerIpInfo, error)
+```
+
+```Go
+func (api *API) ListLoadBalancers(args ...interface{}) ([]LoadBalancer, error)
+```
+
+```Go
+func (api *API) ListLogs(period string, sd *time.Time, ed *time.Time, args ...interface{}) ([]Log, error)
+```
+
+```Go
+func (api *API) ListMonitoringPolicies(args ...interface{}) ([]MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) ListMonitoringPolicyPorts(mp_id string) ([]MonitoringPort, error)
+```
+
+```Go
+func (api *API) ListMonitoringPolicyProcesses(mp_id string) ([]MonitoringProcess, error)
+```
+
+```Go
+func (api *API) ListMonitoringPolicyServers(mp_id string) ([]Identity, error)
+```
+
+```Go
+func (api *API) ListMonitoringServersUsages(args ...interface{}) ([]MonServerUsageSummary, error)
+```
+
+```Go
+func (api *API) ListPrivateNetworkServers(pn_id string) ([]Identity, error)
+```
+
+```Go
+func (api *API) ListPrivateNetworks(args ...interface{}) ([]PrivateNetwork, error)
+```
+
+```Go
+func (api *API) ListPublicIps(args ...interface{}) ([]PublicIp, error)
+```
+
+```Go
+func (api *API) ListRoleUsers(role_id string) ([]Identity, error)
+```
+
+```Go
+func (api *API) ListRoles(args ...interface{}) ([]Role, error)
+```
+
+```Go
+func (api *API) ListServerAppliances(args ...interface{}) ([]ServerAppliance, error)
+```
+
+```Go
+func (api *API) ListServerHdds(server_id string) ([]Hdd, error)
+```
+
+```Go
+func (api *API) ListServerIpLoadBalancers(server_id string, ip_id string) ([]Identity, error)
+```
+
+```Go
+func (api *API) ListServerIps(server_id string) ([]ServerIp, error)
+```
+
+```Go
+func (api *API) ListServerPrivateNetworks(server_id string) ([]Identity, error)
+```
+
+```Go
+func (api *API) ListServers(args ...interface{}) ([]Server, error)
+```
+
+```Go
+func (api *API) ListSharedStorageServers(st_id string) ([]SharedStorageServer, error)
+```
+
+```Go
+func (api *API) ListSharedStorages(args ...interface{}) ([]SharedStorage, error)
+```
+
+```Go
+func (api *API) ListUsages(period string, sd *time.Time, ed *time.Time, args ...interface{}) (*Usages, error)
+```
+
+```Go
+func (api *API) ListUserApiAllowedIps(user_id string) ([]string, error)
+```
+
+```Go
+func (api *API) ListUsers(args ...interface{}) ([]User, error)
+```
+
+```Go
+func (api *API) ListVPNs(args ...interface{}) ([]VPN, error)
+```
+
+```Go
+func (api *API) LoadServerDvd(server_id string, dvd_id string) (*Server, error)
+```
+
+```Go
+func (api *API) ModifyMonitoringPolicyPort(mp_id string, port_id string, mp_port *MonitoringPort) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) ModifyMonitoringPolicyProcess(mp_id string, proc_id string, mp_proc *MonitoringProcess) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) ModifyRole(role_id string, name string, description string, state string) (*Role, error)
+```
+
+```Go
+func (api *API) ModifyRolePermissions(role_id string, perm *Permissions) (*Role, error)
+```
+
+```Go
+func (api *API) ModifyUser(user_id string, user *UserRequest) (*User, error)
+```
+
+```Go
+func (api *API) ModifyUserApi(user_id string, active bool) (*User, error)
+```
+
+```Go
+func (api *API) ModifyVPN(vpn_id string, name string, description string) (*VPN, error)
+```
+
+```Go
+func (api *API) Ping() ([]string, error)
+```
+
+```Go
+func (api *API) PingAuth() ([]string, error)
+```
+
+```Go
+func (api *API) RebootServer(server_id string, is_hardware bool) (*Server, error)
+```
+
+```Go
+func (api *API) ReinstallServerImage(server_id string, image_id string, password string, fp_id string) (*Server, error)
+```
+
+```Go
+func (api *API) RemoveMonitoringPolicyServer(mp_id string, ser_id string) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) RemoveRoleUser(role_id string, user_id string) (*Role, error)
+```
+
+```Go
+func (api *API) RemoveServerPrivateNetwork(server_id string, pn_id string) (*Server, error)
+```
+
+```Go
+func (api *API) RemoveUserApiAllowedIp(user_id string, ip string) (*User, error)
+```
+
+```Go
+func (api *API) RenameServer(server_id string, new_name string, new_desc string) (*Server, error)
+```
+
+```Go
+func (api *API) RenewUserApiKey(user_id string) (*User, error)
+```
+
+```Go
+func (api *API) ResizeServerHdd(server_id string, hdd_id string, new_size int) (*Server, error)
+```
+
+```Go
+func (api *API) RestoreServerSnapshot(server_id string, snapshot_id string) (*Server, error)
+```
+
+```Go
+func (api *API) ShutdownServer(server_id string, is_hardware bool) (*Server, error)
+```
+
+```Go
+func (api *API) StartServer(server_id string) (*Server, error)
+```
+
+```Go
+func (api *API) UnassignServerIpFirewallPolicy(server_id string, ip_id string) (*Server, error)
+```
+
+```Go
+func (api *API) UnassignServerIpLoadBalancer(server_id string, ip_id string, lb_id string) (*Server, error)
+```
+
+```Go
+func (api *API) UpdateFirewallPolicy(fp_id string, fp_new_name string, fp_new_desc string) (*FirewallPolicy, error)
+```
+
+```Go
+func (api *API) UpdateImage(img_id string, new_name string, new_desc string, new_freq string) (*Image, error)
+```
+
+```Go
+func (api *API) UpdateLoadBalancer(lb_id string, request *LoadBalancerRequest) (*LoadBalancer, error)
+```
+
+```Go
+func (api *API) UpdateMonitoringPolicy(mp_id string, mp *MonitoringPolicy) (*MonitoringPolicy, error)
+```
+
+```Go
+func (api *API) UpdatePrivateNetwork(pn_id string, request *PrivateNetworkRequest) (*PrivateNetwork, error)
+```
+
+```Go
+func (api *API) UpdatePublicIp(ip_id string, reverse_dns string) (*PublicIp, error)
+```
+
+```Go
+func (api *API) UpdateServerHardware(server_id string, hardware *Hardware) (*Server, error)
+```
+
+```Go
+func (api *API) UpdateSharedStorage(ss_id string, request *SharedStorageRequest) (*SharedStorage, error)
+```
+
+```Go
+func (api *API) UpdateSharedStorageCredentials(new_pass string) ([]SharedStorageAccess, error)
+```
+
+```Go
+func (api *API) WaitForState(in ApiInstance, state string, sec time.Duration, count int) error
+```
+
+```Go
+func (api *API) WaitUntilDeleted(in ApiInstance) error
+```
+
+```Go
+func (fp *FirewallPolicy) GetState() (string, error)
+```
+
+```Go
+func (im *Image) GetState() (string, error)
+```
+
+```Go
+func (lb *LoadBalancer) GetState() (string, error)
+```
+
+```Go
+func (mp *MonitoringPolicy) GetState() (string, error)
+```
+
+```Go
+func (pn *PrivateNetwork) GetState() (string, error)
+```
+
+```Go
+func (ip *PublicIp) GetState() (string, error)
+```
+
+```Go
+func (role *Role) GetState() (string, error)
+```
+
+```Go
+func (s *Server) GetState() (string, error)
+```
+
+```Go
+func (ss *SharedStorage) GetState() (string, error)
+```
+
+```Go
+func (u *User) GetState() (string, error)
+```
+
+```Go
+func (u *User) GetState() (string, error)
+```
+
+```Go
+func (vpn *VPN) GetState() (string, error)
+```
+
+```Go
+func Bool2Pointer(input bool) *bool
+```
+
+```Go
+func Int2Pointer(input int) *int
+```
+
+```Go
+func (bp *BackupPerm) SetAll(value bool)
+```
+
+```Go
+func (fp *FirewallPerm) SetAll(value bool)
+```
+
+```Go
+func (imp *ImagePerm) SetAll(value bool)
+```
+
+```Go
+unc (inp *InvoicePerm) SetAll(value bool)
+```
+
+```Go
+func (ipp *IPPerm) SetAll(value bool)
+```
+
+```Go
+func (lbp *LoadBalancerPerm) SetAll(value bool)
+```
+
+```Go
+func (lp *LogPerm) SetAll(value bool)
+```
+
+```Go
+func (mcp *MonitorCenterPerm) SetAll(value bool)
+```
+
+```Go
+func (mpp *MonitorPolicyPerm) SetAll(value bool)
+```
+
+```Go
+func (p *Permissions) SetAll(v bool)
+```
+
+```Go
+func (pnp *PrivateNetworkPerm) SetAll(value bool)
+```
+
+```Go
+func (rp *RolePerm) SetAll(value bool)
+```
+
+```Go
+func (sp *ServerPerm) SetAll(value bool)
+```
+
+```Go
+func (ssp *SharedStoragePerm) SetAll(value bool)
+```
+
+```Go
+func (up *UsagePerm) SetAll(value bool)
+```
+
+```Go
+func (up *UserPerm) SetAll(value bool)
+```
+
+```Go
+func (vpnp *VPNPerm) SetAll(value bool)
+```
+
+```Go
+func SetBaseUrl(newbaseurl string) string
+```
+
+```Go
+func SetToken(newtoken string) string
+```
+
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/datacenters.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/datacenters.go
new file mode 100644
index 000000000..cf193fb88
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/datacenters.go
@@ -0,0 +1,36 @@
+package oneandone
+
+import "net/http"
+
+type Datacenter struct {
+ idField
+ CountryCode string `json:"country_code,omitempty"`
+ Location string `json:"location,omitempty"`
+}
+
+// GET /datacenters
+func (api *API) ListDatacenters(args ...interface{}) ([]Datacenter, error) {
+ url, err := processQueryParams(createUrl(api, datacenterPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []Datacenter{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
+
+// GET /datacenters/{datacenter_id}
+func (api *API) GetDatacenter(dc_id string) (*Datacenter, error) {
+ result := new(Datacenter)
+ url := createUrl(api, datacenterPathSegment, dc_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/dvdisos.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/dvdisos.go
new file mode 100644
index 000000000..ba54c3f7f
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/dvdisos.go
@@ -0,0 +1,48 @@
+package oneandone
+
+import "net/http"
+
+// Struct to describe a ISO image that can be used to boot a server.
+//
+// Values of this type describe ISO images that can be inserted into the servers virtual DVD drive.
+//
+//
+type DvdIso struct {
+ Identity
+ OsFamily string `json:"os_family,omitempty"`
+ Os string `json:"os,omitempty"`
+ OsVersion string `json:"os_version,omitempty"`
+ Type string `json:"type,omitempty"`
+ AvailableDatacenters []string `json:"available_datacenters,omitempty"`
+ Architecture interface{} `json:"os_architecture,omitempty"`
+ ApiPtr
+}
+
+// GET /dvd_isos
+func (api *API) ListDvdIsos(args ...interface{}) ([]DvdIso, error) {
+ url, err := processQueryParams(createUrl(api, dvdIsoPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []DvdIso{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// GET /dvd_isos/{id}
+func (api *API) GetDvdIso(dvd_id string) (*DvdIso, error) {
+ result := new(DvdIso)
+ url := createUrl(api, dvdIsoPathSegment, dvd_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/errors.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/errors.go
new file mode 100644
index 000000000..08cc9c250
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/errors.go
@@ -0,0 +1,27 @@
+package oneandone
+
+import (
+ "fmt"
+)
+
+type errorResponse struct {
+ Type string `json:"type"`
+ Message string `json:"message"`
+}
+
+type apiError struct {
+ httpStatusCode int
+ message string
+}
+
+func (e apiError) Error() string {
+ return fmt.Sprintf("%d - %s", e.httpStatusCode, e.message)
+}
+
+func (e *apiError) HttpStatusCode() int {
+ return e.httpStatusCode
+}
+
+func (e *apiError) Message() string {
+ return e.message
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/firewallpolicies.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/firewallpolicies.go
new file mode 100644
index 000000000..3e89c9b17
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/firewallpolicies.go
@@ -0,0 +1,208 @@
+package oneandone
+
+import (
+ "net/http"
+)
+
+type FirewallPolicy struct {
+ Identity
+ descField
+ DefaultPolicy uint8 `json:"default"`
+ CloudpanelId string `json:"cloudpanel_id,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ State string `json:"state,omitempty"`
+ Rules []FirewallPolicyRule `json:"rules,omitempty"`
+ ServerIps []ServerIpInfo `json:"server_ips,omitempty"`
+ ApiPtr
+}
+
+type FirewallPolicyRule struct {
+ idField
+ Protocol string `json:"protocol,omitempty"`
+ PortFrom *int `json:"port_from,omitempty"`
+ PortTo *int `json:"port_to,omitempty"`
+ SourceIp string `json:"source,omitempty"`
+}
+
+type FirewallPolicyRequest struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ Rules []FirewallPolicyRule `json:"rules,omitempty"`
+}
+
+// GET /firewall_policies
+func (api *API) ListFirewallPolicies(args ...interface{}) ([]FirewallPolicy, error) {
+ url, err := processQueryParams(createUrl(api, firewallPolicyPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []FirewallPolicy{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /firewall_policies
+func (api *API) CreateFirewallPolicy(fp_data *FirewallPolicyRequest) (string, *FirewallPolicy, error) {
+ result := new(FirewallPolicy)
+ url := createUrl(api, firewallPolicyPathSegment)
+ err := api.Client.Post(url, &fp_data, &result, http.StatusAccepted)
+ if err != nil {
+ return "", nil, err
+ }
+ result.api = api
+ return result.Id, result, nil
+}
+
+// GET /firewall_policies/{id}
+func (api *API) GetFirewallPolicy(fp_id string) (*FirewallPolicy, error) {
+ result := new(FirewallPolicy)
+ url := createUrl(api, firewallPolicyPathSegment, fp_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+
+}
+
+// DELETE /firewall_policies/{id}
+func (api *API) DeleteFirewallPolicy(fp_id string) (*FirewallPolicy, error) {
+ result := new(FirewallPolicy)
+ url := createUrl(api, firewallPolicyPathSegment, fp_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /firewall_policies/{id}
+func (api *API) UpdateFirewallPolicy(fp_id string, fp_new_name string, fp_new_desc string) (*FirewallPolicy, error) {
+ result := new(FirewallPolicy)
+ data := FirewallPolicyRequest{
+ Name: fp_new_name,
+ Description: fp_new_desc,
+ }
+ url := createUrl(api, firewallPolicyPathSegment, fp_id)
+ err := api.Client.Put(url, &data, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /firewall_policies/{id}/server_ips
+func (api *API) ListFirewallPolicyServerIps(fp_id string) ([]ServerIpInfo, error) {
+ result := []ServerIpInfo{}
+ url := createUrl(api, firewallPolicyPathSegment, fp_id, "server_ips")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// GET /firewall_policies/{id}/server_ips/{id}
+func (api *API) GetFirewallPolicyServerIp(fp_id string, ip_id string) (*ServerIpInfo, error) {
+ result := new(ServerIpInfo)
+ url := createUrl(api, firewallPolicyPathSegment, fp_id, "server_ips", ip_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /firewall_policies/{id}/server_ips
+func (api *API) AddFirewallPolicyServerIps(fp_id string, ip_ids []string) (*FirewallPolicy, error) {
+ result := new(FirewallPolicy)
+ request := serverIps{
+ ServerIps: ip_ids,
+ }
+
+ url := createUrl(api, firewallPolicyPathSegment, fp_id, "server_ips")
+ err := api.Client.Post(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /firewall_policies/{id}/server_ips/{id}
+func (api *API) DeleteFirewallPolicyServerIp(fp_id string, ip_id string) (*FirewallPolicy, error) {
+ result := new(FirewallPolicy)
+ url := createUrl(api, firewallPolicyPathSegment, fp_id, "server_ips", ip_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /firewall_policies/{id}/rules
+func (api *API) ListFirewallPolicyRules(fp_id string) ([]FirewallPolicyRule, error) {
+ result := []FirewallPolicyRule{}
+ url := createUrl(api, firewallPolicyPathSegment, fp_id, "rules")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /firewall_policies/{id}/rules
+func (api *API) AddFirewallPolicyRules(fp_id string, fp_rules []FirewallPolicyRule) (*FirewallPolicy, error) {
+ result := new(FirewallPolicy)
+ data := struct {
+ Rules []FirewallPolicyRule `json:"rules"`
+ }{fp_rules}
+ url := createUrl(api, firewallPolicyPathSegment, fp_id, "rules")
+ err := api.Client.Post(url, &data, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /firewall_policies/{id}/rules/{id}
+func (api *API) GetFirewallPolicyRule(fp_id string, rule_id string) (*FirewallPolicyRule, error) {
+ result := new(FirewallPolicyRule)
+ url := createUrl(api, firewallPolicyPathSegment, fp_id, "rules", rule_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /firewall_policies/{id}/rules/{id}
+func (api *API) DeleteFirewallPolicyRule(fp_id string, rule_id string) (*FirewallPolicy, error) {
+ result := new(FirewallPolicy)
+ url := createUrl(api, firewallPolicyPathSegment, fp_id, "rules", rule_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+func (fp *FirewallPolicy) GetState() (string, error) {
+ in, err := fp.api.GetFirewallPolicy(fp.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/images.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/images.go
new file mode 100644
index 000000000..a3551cef7
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/images.go
@@ -0,0 +1,110 @@
+package oneandone
+
+import (
+ "net/http"
+)
+
+type Image struct {
+ idField
+ ImageConfig
+ MinHddSize int `json:"min_hdd_size"`
+ Architecture *int `json:"os_architecture"`
+ CloudPanelId string `json:"cloudpanel_id,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ State string `json:"state,omitempty"`
+ OsImageType string `json:"os_image_type,omitempty"`
+ OsFamily string `json:"os_family,omitempty"`
+ Os string `json:"os,omitempty"`
+ OsVersion string `json:"os_version,omitempty"`
+ Type string `json:"type,omitempty"`
+ Licenses []License `json:"licenses,omitempty"`
+ Hdds []Hdd `json:"hdds,omitempty"`
+ Datacenter *Datacenter `json:"datacenter,omitempty"`
+ ApiPtr
+}
+
+type ImageConfig struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ Frequency string `json:"frequency,omitempty"`
+ ServerId string `json:"server_id,omitempty"`
+ NumImages int `json:"num_images"`
+}
+
+// GET /images
+func (api *API) ListImages(args ...interface{}) ([]Image, error) {
+ url, err := processQueryParams(createUrl(api, imagePathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []Image{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /images
+func (api *API) CreateImage(request *ImageConfig) (string, *Image, error) {
+ res := new(Image)
+ url := createUrl(api, imagePathSegment)
+ err := api.Client.Post(url, &request, &res, http.StatusAccepted)
+ if err != nil {
+ return "", nil, err
+ }
+ res.api = api
+ return res.Id, res, nil
+}
+
+// GET /images/{id}
+func (api *API) GetImage(img_id string) (*Image, error) {
+ result := new(Image)
+ url := createUrl(api, imagePathSegment, img_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /images/{id}
+func (api *API) DeleteImage(img_id string) (*Image, error) {
+ result := new(Image)
+ url := createUrl(api, imagePathSegment, img_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /images/{id}
+func (api *API) UpdateImage(img_id string, new_name string, new_desc string, new_freq string) (*Image, error) {
+ result := new(Image)
+ req := struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ Frequency string `json:"frequency,omitempty"`
+ }{Name: new_name, Description: new_desc, Frequency: new_freq}
+ url := createUrl(api, imagePathSegment, img_id)
+ err := api.Client.Put(url, &req, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+func (im *Image) GetState() (string, error) {
+ in, err := im.api.GetImage(im.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/loadbalancers.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/loadbalancers.go
new file mode 100644
index 000000000..c965a25a8
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/loadbalancers.go
@@ -0,0 +1,219 @@
+package oneandone
+
+import (
+ "net/http"
+)
+
+type LoadBalancer struct {
+ ApiPtr
+ idField
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ State string `json:"state,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ Ip string `json:"ip,omitempty"`
+ HealthCheckTest string `json:"health_check_test,omitempty"`
+ HealthCheckInterval int `json:"health_check_interval"`
+ HealthCheckPath string `json:"health_check_path,omitempty"`
+ HealthCheckPathParser string `json:"health_check_path_parser,omitempty"`
+ Persistence bool `json:"persistence"`
+ PersistenceTime int `json:"persistence_time"`
+ Method string `json:"method,omitempty"`
+ Rules []LoadBalancerRule `json:"rules,omitempty"`
+ ServerIps []ServerIpInfo `json:"server_ips,omitempty"`
+ Datacenter *Datacenter `json:"datacenter,omitempty"`
+ CloudPanelId string `json:"cloudpanel_id,omitempty"`
+}
+
+type LoadBalancerRule struct {
+ idField
+ Protocol string `json:"protocol,omitempty"`
+ PortBalancer uint16 `json:"port_balancer"`
+ PortServer uint16 `json:"port_server"`
+ Source string `json:"source,omitempty"`
+}
+
+type LoadBalancerRequest struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ DatacenterId string `json:"datacenter_id,omitempty"`
+ HealthCheckTest string `json:"health_check_test,omitempty"`
+ HealthCheckInterval *int `json:"health_check_interval"`
+ HealthCheckPath string `json:"health_check_path,omitempty"`
+ HealthCheckPathParser string `json:"health_check_path_parser,omitempty"`
+ Persistence *bool `json:"persistence"`
+ PersistenceTime *int `json:"persistence_time"`
+ Method string `json:"method,omitempty"`
+ Rules []LoadBalancerRule `json:"rules,omitempty"`
+}
+
+// GET /load_balancers
+func (api *API) ListLoadBalancers(args ...interface{}) ([]LoadBalancer, error) {
+ url, err := processQueryParams(createUrl(api, loadBalancerPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []LoadBalancer{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /load_balancers
+func (api *API) CreateLoadBalancer(request *LoadBalancerRequest) (string, *LoadBalancer, error) {
+ url := createUrl(api, loadBalancerPathSegment)
+ result := new(LoadBalancer)
+ err := api.Client.Post(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return "", nil, err
+ }
+ result.api = api
+ return result.Id, result, nil
+}
+
+// GET /load_balancers/{id}
+func (api *API) GetLoadBalancer(lb_id string) (*LoadBalancer, error) {
+ url := createUrl(api, loadBalancerPathSegment, lb_id)
+ result := new(LoadBalancer)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /load_balancers/{id}
+func (api *API) DeleteLoadBalancer(lb_id string) (*LoadBalancer, error) {
+ url := createUrl(api, loadBalancerPathSegment, lb_id)
+ result := new(LoadBalancer)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /load_balancers/{id}
+func (api *API) UpdateLoadBalancer(lb_id string, request *LoadBalancerRequest) (*LoadBalancer, error) {
+ url := createUrl(api, loadBalancerPathSegment, lb_id)
+ result := new(LoadBalancer)
+ err := api.Client.Put(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /load_balancers/{id}/server_ips
+func (api *API) ListLoadBalancerServerIps(lb_id string) ([]ServerIpInfo, error) {
+ result := []ServerIpInfo{}
+ url := createUrl(api, loadBalancerPathSegment, lb_id, "server_ips")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// GET /load_balancers/{id}/server_ips/{id}
+func (api *API) GetLoadBalancerServerIp(lb_id string, ip_id string) (*ServerIpInfo, error) {
+ result := new(ServerIpInfo)
+ url := createUrl(api, loadBalancerPathSegment, lb_id, "server_ips", ip_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /load_balancers/{id}/server_ips
+func (api *API) AddLoadBalancerServerIps(lb_id string, ip_ids []string) (*LoadBalancer, error) {
+ result := new(LoadBalancer)
+ request := serverIps{
+ ServerIps: ip_ids,
+ }
+ url := createUrl(api, loadBalancerPathSegment, lb_id, "server_ips")
+ err := api.Client.Post(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /load_balancers/{id}/server_ips/{id}
+func (api *API) DeleteLoadBalancerServerIp(lb_id string, ip_id string) (*LoadBalancer, error) {
+ result := new(LoadBalancer)
+ url := createUrl(api, loadBalancerPathSegment, lb_id, "server_ips", ip_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /load_balancers/{load_balancer_id}/rules
+func (api *API) ListLoadBalancerRules(lb_id string) ([]LoadBalancerRule, error) {
+ result := []LoadBalancerRule{}
+ url := createUrl(api, loadBalancerPathSegment, lb_id, "rules")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /load_balancers/{load_balancer_id}/rules
+func (api *API) AddLoadBalancerRules(lb_id string, lb_rules []LoadBalancerRule) (*LoadBalancer, error) {
+ result := new(LoadBalancer)
+ data := struct {
+ Rules []LoadBalancerRule `json:"rules"`
+ }{lb_rules}
+ url := createUrl(api, loadBalancerPathSegment, lb_id, "rules")
+ err := api.Client.Post(url, &data, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /load_balancers/{load_balancer_id}/rules/{rule_id}
+func (api *API) GetLoadBalancerRule(lb_id string, rule_id string) (*LoadBalancerRule, error) {
+ result := new(LoadBalancerRule)
+ url := createUrl(api, loadBalancerPathSegment, lb_id, "rules", rule_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /load_balancers/{load_balancer_id}/rules/{rule_id}
+func (api *API) DeleteLoadBalancerRule(lb_id string, rule_id string) (*LoadBalancer, error) {
+ result := new(LoadBalancer)
+ url := createUrl(api, loadBalancerPathSegment, lb_id, "rules", rule_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+func (lb *LoadBalancer) GetState() (string, error) {
+ in, err := lb.api.GetLoadBalancer(lb.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/logs.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/logs.go
new file mode 100644
index 000000000..b16ef31d5
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/logs.go
@@ -0,0 +1,50 @@
+package oneandone
+
+import (
+ "net/http"
+ "time"
+)
+
+type Log struct {
+ ApiPtr
+ idField
+ typeField
+ CloudPanelId string `json:"cloudpanel_id,omitempty"`
+ SiteId string `json:"site_id,omitempty"`
+ StartDate string `json:"start_date,omitempty"`
+ EndDate string `json:"end_date,omitempty"`
+ Action string `json:"action,omitempty"`
+ Duration int `json:"duration"`
+ Status *Status `json:"Status,omitempty"`
+ Resource *Identity `json:"resource,omitempty"`
+ User *Identity `json:"user,omitempty"`
+}
+
+// GET /logs
+func (api *API) ListLogs(period string, sd *time.Time, ed *time.Time, args ...interface{}) ([]Log, error) {
+ result := []Log{}
+ url, err := processQueryParamsExt(createUrl(api, logPathSegment), period, sd, ed, args...)
+ if err != nil {
+ return nil, err
+ }
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// GET /logs/{id}
+func (api *API) GetLog(log_id string) (*Log, error) {
+ result := new(Log)
+ url := createUrl(api, logPathSegment, log_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/monitoringcenter.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/monitoringcenter.go
new file mode 100644
index 000000000..86e899889
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/monitoringcenter.go
@@ -0,0 +1,158 @@
+package oneandone
+
+import (
+ "errors"
+ "net/http"
+ "time"
+)
+
+type MonServerUsageSummary struct {
+ Identity
+ Agent *monitoringAgent `json:"agent,omitempty"`
+ Alerts *monitoringAlerts `json:"alerts,omitempty"`
+ Status *monitoringStatus `json:"status,omitempty"`
+ ApiPtr
+}
+
+type MonServerUsageDetails struct {
+ Identity
+ Status *statusState `json:"status,omitempty"`
+ Agent *monitoringAgent `json:"agent,omitempty"`
+ Alerts *monitoringAlerts `json:"alerts,omitempty"`
+ CpuStatus *utilizationStatus `json:"cpu,omitempty"`
+ DiskStatus *utilizationStatus `json:"disk,omitempty"`
+ RamStatus *utilizationStatus `json:"ram,omitempty"`
+ PingStatus *pingStatus `json:"internal_ping,omitempty"`
+ TransferStatus *transferStatus `json:"transfer,omitempty"`
+ ApiPtr
+}
+
+type monitoringStatus struct {
+ State string `json:"state,omitempty"`
+ Cpu *statusState `json:"cpu,omitempty"`
+ Disk *statusState `json:"disk,omitempty"`
+ InternalPing *statusState `json:"internal_ping,omitempty"`
+ Ram *statusState `json:"ram,omitempty"`
+ Transfer *statusState `json:"transfer,omitempty"`
+}
+
+type utilizationStatus struct {
+ CriticalThreshold int `json:"critical,omitempty"`
+ WarningThreshold int `json:"warning,omitempty"`
+ Status string `json:"status,omitempty"`
+ Data []usageData `json:"data,omitempty"`
+ Unit *usageUnit `json:"unit,omitempty"`
+}
+
+type pingStatus struct {
+ CriticalThreshold int `json:"critical,omitempty"`
+ WarningThreshold int `json:"warning,omitempty"`
+ Status string `json:"status,omitempty"`
+ Data []pingData `json:"data,omitempty"`
+ Unit *pingUnit `json:"unit,omitempty"`
+}
+
+type transferStatus struct {
+ CriticalThreshold int `json:"critical,omitempty"`
+ WarningThreshold int `json:"warning,omitempty"`
+ Status string `json:"status,omitempty"`
+ Data []transferData `json:"data,omitempty"`
+ Unit *transferUnit `json:"unit,omitempty"`
+}
+
+type monitoringAgent struct {
+ AgentInstalled bool `json:"agent_installed"`
+ MissingAgentAlert bool `json:"missing_agent_alert"`
+ MonitoringNeedsAgent bool `json:"monitoring_needs_agent"`
+}
+
+type monitoringAlerts struct {
+ Ports *monitoringAlertInfo `json:"ports,omitempty"`
+ Process *monitoringAlertInfo `json:"process,omitempty"`
+ Resources *monitoringAlertInfo `json:"resources,omitempty"`
+}
+
+type monitoringAlertInfo struct {
+ Ok int `json:"ok"`
+ Warning int `json:"warning"`
+ Critical int `json:"critical"`
+}
+
+type usageData struct {
+ Date string `json:"date,omitempty"`
+ UsedPercent float32 `json:"used_percent"`
+}
+
+type usageUnit struct {
+ UsedPercent string `json:"used_percent,omitempty"`
+}
+
+type pingUnit struct {
+ PackagesLost string `json:"pl,omitempty"`
+ AccessTime string `json:"rta,omitempty"`
+}
+
+type pingData struct {
+ Date string `json:"date,omitempty"`
+ PackagesLost int `json:"pl"`
+ AccessTime float32 `json:"rta"`
+}
+
+type transferUnit struct {
+ Downstream string `json:"downstream,omitempty"`
+ Upstream string `json:"upstream,omitempty"`
+}
+
+type transferData struct {
+ Date string `json:"date,omitempty"`
+ Downstream int `json:"downstream"`
+ Upstream int `json:"upstream"`
+}
+
+// GET /monitoring_center
+func (api *API) ListMonitoringServersUsages(args ...interface{}) ([]MonServerUsageSummary, error) {
+ url, err := processQueryParams(createUrl(api, monitorCenterPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []MonServerUsageSummary{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// GET /monitoring_center/{server_id}
+func (api *API) GetMonitoringServerUsage(ser_id string, period string, dates ...time.Time) (*MonServerUsageDetails, error) {
+ if period == "" {
+ return nil, errors.New("Time period must be provided.")
+ }
+
+ params := make(map[string]interface{}, len(dates)+1)
+ params["period"] = period
+
+ if len(dates) == 2 {
+ if dates[0].After(dates[1]) {
+ return nil, errors.New("Start date cannot be after end date.")
+ }
+
+ params["start_date"] = dates[0].Format(time.RFC3339)
+ params["end_date"] = dates[1].Format(time.RFC3339)
+
+ } else if len(dates) > 0 {
+ return nil, errors.New("Start and end dates must be provided.")
+ }
+ url := createUrl(api, monitorCenterPathSegment, ser_id)
+ url = appendQueryParams(url, params)
+ result := new(MonServerUsageDetails)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/monitoringpolicies.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/monitoringpolicies.go
new file mode 100644
index 000000000..4272461b6
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/monitoringpolicies.go
@@ -0,0 +1,305 @@
+package oneandone
+
+import (
+ "net/http"
+)
+
+type MonitoringPolicy struct {
+ ApiPtr
+ idField
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ State string `json:"state,omitempty"`
+ Default *int `json:"default,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ Email string `json:"email,omitempty"`
+ Agent bool `json:"agent"`
+ Servers []Identity `json:"servers,omitempty"`
+ Thresholds *MonitoringThreshold `json:"thresholds,omitempty"`
+ Ports []MonitoringPort `json:"ports,omitempty"`
+ Processes []MonitoringProcess `json:"processes,omitempty"`
+ CloudPanelId string `json:"cloudpanel_id,omitempty"`
+}
+
+type MonitoringThreshold struct {
+ Cpu *MonitoringLevel `json:"cpu,omitempty"`
+ Ram *MonitoringLevel `json:"ram,omitempty"`
+ Disk *MonitoringLevel `json:"disk,omitempty"`
+ Transfer *MonitoringLevel `json:"transfer,omitempty"`
+ InternalPing *MonitoringLevel `json:"internal_ping,omitempty"`
+}
+
+type MonitoringLevel struct {
+ Warning *MonitoringValue `json:"warning,omitempty"`
+ Critical *MonitoringValue `json:"critical,omitempty"`
+}
+
+type MonitoringValue struct {
+ Value int `json:"value"`
+ Alert bool `json:"alert"`
+}
+
+type MonitoringPort struct {
+ idField
+ Protocol string `json:"protocol,omitempty"`
+ Port int `json:"port"`
+ AlertIf string `json:"alert_if,omitempty"`
+ EmailNotification bool `json:"email_notification"`
+}
+
+type MonitoringProcess struct {
+ idField
+ Process string `json:"process,omitempty"`
+ AlertIf string `json:"alert_if,omitempty"`
+ EmailNotification bool `json:"email_notification"`
+}
+
+// GET /monitoring_policies
+func (api *API) ListMonitoringPolicies(args ...interface{}) ([]MonitoringPolicy, error) {
+ url, err := processQueryParams(createUrl(api, monitorPolicyPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []MonitoringPolicy{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /monitoring_policies
+func (api *API) CreateMonitoringPolicy(mp *MonitoringPolicy) (string, *MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ url := createUrl(api, monitorPolicyPathSegment)
+ err := api.Client.Post(url, &mp, &result, http.StatusCreated)
+ if err != nil {
+ return "", nil, err
+ }
+ result.api = api
+ return result.Id, result, nil
+}
+
+// GET /monitoring_policies/{id}
+func (api *API) GetMonitoringPolicy(mp_id string) (*MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ url := createUrl(api, monitorPolicyPathSegment, mp_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /monitoring_policies/{id}
+func (api *API) DeleteMonitoringPolicy(mp_id string) (*MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ url := createUrl(api, monitorPolicyPathSegment, mp_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /monitoring_policies/{id}
+func (api *API) UpdateMonitoringPolicy(mp_id string, mp *MonitoringPolicy) (*MonitoringPolicy, error) {
+ url := createUrl(api, monitorPolicyPathSegment, mp_id)
+ result := new(MonitoringPolicy)
+ err := api.Client.Put(url, &mp, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /monitoring_policies/{id}/ports
+func (api *API) ListMonitoringPolicyPorts(mp_id string) ([]MonitoringPort, error) {
+ result := []MonitoringPort{}
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "ports")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /monitoring_policies/{id}/ports
+func (api *API) AddMonitoringPolicyPorts(mp_id string, mp_ports []MonitoringPort) (*MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ data := struct {
+ Ports []MonitoringPort `json:"ports"`
+ }{mp_ports}
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "ports")
+ err := api.Client.Post(url, &data, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /monitoring_policies/{id}/ports/{id}
+func (api *API) GetMonitoringPolicyPort(mp_id string, port_id string) (*MonitoringPort, error) {
+ result := new(MonitoringPort)
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "ports", port_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /monitoring_policies/{id}/ports/{id}
+func (api *API) DeleteMonitoringPolicyPort(mp_id string, port_id string) (*MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "ports", port_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /monitoring_policies/{id}/ports/{id}
+func (api *API) ModifyMonitoringPolicyPort(mp_id string, port_id string, mp_port *MonitoringPort) (*MonitoringPolicy, error) {
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "ports", port_id)
+ result := new(MonitoringPolicy)
+ req := struct {
+ Ports *MonitoringPort `json:"ports"`
+ }{mp_port}
+ err := api.Client.Put(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /monitoring_policies/{id}/processes
+func (api *API) ListMonitoringPolicyProcesses(mp_id string) ([]MonitoringProcess, error) {
+ result := []MonitoringProcess{}
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "processes")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /monitoring_policies/{id}/processes
+func (api *API) AddMonitoringPolicyProcesses(mp_id string, mp_procs []MonitoringProcess) (*MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ request := struct {
+ Processes []MonitoringProcess `json:"processes"`
+ }{mp_procs}
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "processes")
+ err := api.Client.Post(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /monitoring_policies/{id}/processes/{id}
+func (api *API) GetMonitoringPolicyProcess(mp_id string, proc_id string) (*MonitoringProcess, error) {
+ result := new(MonitoringProcess)
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "processes", proc_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /monitoring_policies/{id}/processes/{id}
+func (api *API) DeleteMonitoringPolicyProcess(mp_id string, proc_id string) (*MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "processes", proc_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /monitoring_policies/{id}/processes/{id}
+func (api *API) ModifyMonitoringPolicyProcess(mp_id string, proc_id string, mp_proc *MonitoringProcess) (*MonitoringPolicy, error) {
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "processes", proc_id)
+ result := new(MonitoringPolicy)
+ req := struct {
+ Processes *MonitoringProcess `json:"processes"`
+ }{mp_proc}
+ err := api.Client.Put(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /monitoring_policies/{id}/servers
+func (api *API) ListMonitoringPolicyServers(mp_id string) ([]Identity, error) {
+ result := []Identity{}
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "servers")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /monitoring_policies/{id}/servers
+func (api *API) AttachMonitoringPolicyServers(mp_id string, sids []string) (*MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ request := servers{
+ Servers: sids,
+ }
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "servers")
+ err := api.Client.Post(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /monitoring_policies/{id}/servers/{id}
+func (api *API) GetMonitoringPolicyServer(mp_id string, ser_id string) (*Identity, error) {
+ result := new(Identity)
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "servers", ser_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /monitoring_policies/{id}/servers/{id}
+func (api *API) RemoveMonitoringPolicyServer(mp_id string, ser_id string) (*MonitoringPolicy, error) {
+ result := new(MonitoringPolicy)
+ url := createUrl(api, monitorPolicyPathSegment, mp_id, "servers", ser_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+func (mp *MonitoringPolicy) GetState() (string, error) {
+ in, err := mp.api.GetMonitoringPolicy(mp.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/oneandone.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/oneandone.go
new file mode 100644
index 000000000..e007fcb22
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/oneandone.go
@@ -0,0 +1,163 @@
+package oneandone
+
+import (
+ "errors"
+ "net/http"
+ "reflect"
+ "time"
+)
+
+// Struct to hold the required information for accessing the API.
+//
+// Instances of this type contain the URL of the endpoint to access the API as well as the API access token to be used.
+// They offer also all methods that allow to access the various objects that are returned by top level resources of
+// the API.
+type API struct {
+ Endpoint string
+ Client *restClient
+}
+
+type ApiPtr struct {
+ api *API
+}
+
+type idField struct {
+ Id string `json:"id,omitempty"`
+}
+
+type typeField struct {
+ Type string `json:"type,omitempty"`
+}
+
+type nameField struct {
+ Name string `json:"name,omitempty"`
+}
+
+type descField struct {
+ Description string `json:"description,omitempty"`
+}
+
+type countField struct {
+ Count int `json:"count,omitempty"`
+}
+
+type serverIps struct {
+ ServerIps []string `json:"server_ips"`
+}
+
+type servers struct {
+ Servers []string `json:"servers"`
+}
+
+type ApiInstance interface {
+ GetState() (string, error)
+}
+
+const (
+ datacenterPathSegment = "datacenters"
+ dvdIsoPathSegment = "dvd_isos"
+ firewallPolicyPathSegment = "firewall_policies"
+ imagePathSegment = "images"
+ loadBalancerPathSegment = "load_balancers"
+ logPathSegment = "logs"
+ monitorCenterPathSegment = "monitoring_center"
+ monitorPolicyPathSegment = "monitoring_policies"
+ pingPathSegment = "ping"
+ pingAuthPathSegment = "ping_auth"
+ pricingPathSegment = "pricing"
+ privateNetworkPathSegment = "private_networks"
+ publicIpPathSegment = "public_ips"
+ rolePathSegment = "roles"
+ serverPathSegment = "servers"
+ serverAppliancePathSegment = "server_appliances"
+ sharedStoragePathSegment = "shared_storages"
+ usagePathSegment = "usages"
+ userPathSegment = "users"
+ vpnPathSegment = "vpns"
+)
+
+// Struct to hold the status of an API object.
+//
+// Values of this type are used to represent the status of API objects like servers, firewall policies and the like.
+//
+// The value of the "State" field can represent fixed states like "ACTIVE" or "POWERED_ON" but also transitional
+// states like "POWERING_ON" or "CONFIGURING".
+//
+// For fixed states the "Percent" field is empty where as for transitional states it contains the progress of the
+// transition in percent.
+type Status struct {
+ State string `json:"state"`
+ Percent int `json:"percent"`
+}
+
+type statusState struct {
+ State string `json:"state,omitempty"`
+}
+
+type Identity struct {
+ idField
+ nameField
+}
+
+type License struct {
+ nameField
+}
+
+// Creates a new API instance.
+//
+// Explanations about given token and url information can be found online under the following url TODO add url!
+func New(token string, url string) *API {
+ api := new(API)
+ api.Endpoint = url
+ api.Client = newRestClient(token)
+ return api
+}
+
+// Converts a given integer value into a pointer of the same type.
+func Int2Pointer(input int) *int {
+ result := new(int)
+ *result = input
+ return result
+}
+
+// Converts a given boolean value into a pointer of the same type.
+func Bool2Pointer(input bool) *bool {
+ result := new(bool)
+ *result = input
+ return result
+}
+
+// Performs busy-waiting for types that implement ApiInstance interface.
+func (api *API) WaitForState(in ApiInstance, state string, sec time.Duration, count int) error {
+ if in != nil {
+ for i := 0; i < count; i++ {
+ s, err := in.GetState()
+ if err != nil {
+ return err
+ }
+ if s == state {
+ return nil
+ }
+ time.Sleep(sec * time.Second)
+ }
+ return errors.New(reflect.ValueOf(in).Type().String() + " operation timeout.")
+ }
+ return nil
+}
+
+// Waits until instance is deleted for types that implement ApiInstance interface.
+func (api *API) WaitUntilDeleted(in ApiInstance) error {
+ var err error
+ for in != nil {
+ _, err = in.GetState()
+ if err != nil {
+ if apiError, ok := err.(apiError); ok && apiError.httpStatusCode == http.StatusNotFound {
+ return nil
+ } else {
+ return err
+ }
+ }
+ time.Sleep(5 * time.Second)
+ }
+ return nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/ping.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/ping.go
new file mode 100644
index 000000000..255608885
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/ping.go
@@ -0,0 +1,29 @@
+package oneandone
+
+import "net/http"
+
+// GET /ping
+// Returns "PONG" if API is running
+func (api *API) Ping() ([]string, error) {
+ url := createUrl(api, pingPathSegment)
+ result := []string{}
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
+
+// GET /ping_auth
+// Returns "PONG" if the API is running and the authentication token is valid
+func (api *API) PingAuth() ([]string, error) {
+ url := createUrl(api, pingAuthPathSegment)
+ result := []string{}
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/pricing.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/pricing.go
new file mode 100644
index 000000000..90eb2abd9
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/pricing.go
@@ -0,0 +1,40 @@
+package oneandone
+
+import "net/http"
+
+type Pricing struct {
+ Currency string `json:"currency,omitempty"`
+ Plan *pricingPlan `json:"pricing_plans,omitempty"`
+}
+
+type pricingPlan struct {
+ Image *pricingItem `json:"image,omitempty"`
+ PublicIPs []pricingItem `json:"public_ips,omitempty"`
+ Servers *serverPricing `json:"servers,omitempty"`
+ SharedStorage *pricingItem `json:"shared_storage,omitempty"`
+ SoftwareLicenses []pricingItem `json:"software_licences,omitempty"`
+}
+
+type serverPricing struct {
+ FixedServers []pricingItem `json:"fixed_servers,omitempty"`
+ FlexServers []pricingItem `json:"flexible_server,omitempty"`
+}
+
+type pricingItem struct {
+ Name string `json:"name,omitempty"`
+ GrossPrice string `json:"price_gross,omitempty"`
+ NetPrice string `json:"price_net,omitempty"`
+ Unit string `json:"unit,omitempty"`
+}
+
+// GET /pricing
+func (api *API) GetPricing() (*Pricing, error) {
+ result := new(Pricing)
+ url := createUrl(api, pricingPathSegment)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/privatenetworks.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/privatenetworks.go
new file mode 100644
index 000000000..667494e04
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/privatenetworks.go
@@ -0,0 +1,149 @@
+package oneandone
+
+import (
+ "net/http"
+)
+
+type PrivateNetwork struct {
+ Identity
+ descField
+ CloudpanelId string `json:"cloudpanel_id,omitempty"`
+ NetworkAddress string `json:"network_address,omitempty"`
+ SubnetMask string `json:"subnet_mask,omitempty"`
+ State string `json:"state,omitempty"`
+ SiteId string `json:"site_id,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ Servers []Identity `json:"servers,omitempty"`
+ Datacenter *Datacenter `json:"datacenter,omitempty"`
+ ApiPtr
+}
+
+type PrivateNetworkRequest struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ DatacenterId string `json:"datacenter_id,omitempty"`
+ NetworkAddress string `json:"network_address,omitempty"`
+ SubnetMask string `json:"subnet_mask,omitempty"`
+}
+
+// GET /private_networks
+func (api *API) ListPrivateNetworks(args ...interface{}) ([]PrivateNetwork, error) {
+ url, err := processQueryParams(createUrl(api, privateNetworkPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []PrivateNetwork{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /private_networks
+func (api *API) CreatePrivateNetwork(request *PrivateNetworkRequest) (string, *PrivateNetwork, error) {
+ result := new(PrivateNetwork)
+ url := createUrl(api, privateNetworkPathSegment)
+ err := api.Client.Post(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return "", nil, err
+ }
+ result.api = api
+ return result.Id, result, nil
+}
+
+// GET /private_networks/{id}
+func (api *API) GetPrivateNetwork(pn_id string) (*PrivateNetwork, error) {
+ result := new(PrivateNetwork)
+ url := createUrl(api, privateNetworkPathSegment, pn_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /private_networks/{id}
+func (api *API) UpdatePrivateNetwork(pn_id string, request *PrivateNetworkRequest) (*PrivateNetwork, error) {
+ result := new(PrivateNetwork)
+ url := createUrl(api, privateNetworkPathSegment, pn_id)
+ err := api.Client.Put(url, &request, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /private_networks/{id}
+func (api *API) DeletePrivateNetwork(pn_id string) (*PrivateNetwork, error) {
+ result := new(PrivateNetwork)
+ url := createUrl(api, privateNetworkPathSegment, pn_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /private_networks/{id}/servers
+func (api *API) ListPrivateNetworkServers(pn_id string) ([]Identity, error) {
+ result := []Identity{}
+ url := createUrl(api, privateNetworkPathSegment, pn_id, "servers")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /private_networks/{id}/servers
+func (api *API) AttachPrivateNetworkServers(pn_id string, sids []string) (*PrivateNetwork, error) {
+ result := new(PrivateNetwork)
+ req := servers{
+ Servers: sids,
+ }
+ url := createUrl(api, privateNetworkPathSegment, pn_id, "servers")
+ err := api.Client.Post(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /private_networks/{id}/servers/{id}
+func (api *API) GetPrivateNetworkServer(pn_id string, server_id string) (*Identity, error) {
+ result := new(Identity)
+ url := createUrl(api, privateNetworkPathSegment, pn_id, "servers", server_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /private_networks/{id}/servers/{id}
+func (api *API) DetachPrivateNetworkServer(pn_id string, pns_id string) (*PrivateNetwork, error) {
+ result := new(PrivateNetwork)
+ url := createUrl(api, privateNetworkPathSegment, pn_id, "servers", pns_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+func (pn *PrivateNetwork) GetState() (string, error) {
+ in, err := pn.api.GetPrivateNetwork(pn.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/publicips.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/publicips.go
new file mode 100644
index 000000000..b0b6bd6ed
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/publicips.go
@@ -0,0 +1,108 @@
+package oneandone
+
+import "net/http"
+
+type PublicIp struct {
+ idField
+ typeField
+ IpAddress string `json:"ip,omitempty"`
+ AssignedTo *assignedTo `json:"assigned_to,omitempty"`
+ ReverseDns string `json:"reverse_dns,omitempty"`
+ IsDhcp *bool `json:"is_dhcp,omitempty"`
+ State string `json:"state,omitempty"`
+ SiteId string `json:"site_id,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ Datacenter *Datacenter `json:"datacenter,omitempty"`
+ ApiPtr
+}
+
+type assignedTo struct {
+ Identity
+ typeField
+}
+
+const (
+ IpTypeV4 = "IPV4"
+ IpTypeV6 = "IPV6"
+)
+
+// GET /public_ips
+func (api *API) ListPublicIps(args ...interface{}) ([]PublicIp, error) {
+ url, err := processQueryParams(createUrl(api, publicIpPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []PublicIp{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /public_ips
+func (api *API) CreatePublicIp(ip_type string, reverse_dns string, datacenter_id string) (string, *PublicIp, error) {
+ res := new(PublicIp)
+ url := createUrl(api, publicIpPathSegment)
+ req := struct {
+ DatacenterId string `json:"datacenter_id,omitempty"`
+ ReverseDns string `json:"reverse_dns,omitempty"`
+ Type string `json:"type,omitempty"`
+ }{DatacenterId: datacenter_id, ReverseDns: reverse_dns, Type: ip_type}
+ err := api.Client.Post(url, &req, &res, http.StatusCreated)
+ if err != nil {
+ return "", nil, err
+ }
+ res.api = api
+ return res.Id, res, nil
+}
+
+// GET /public_ips/{id}
+func (api *API) GetPublicIp(ip_id string) (*PublicIp, error) {
+ result := new(PublicIp)
+ url := createUrl(api, publicIpPathSegment, ip_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /public_ips/{id}
+func (api *API) DeletePublicIp(ip_id string) (*PublicIp, error) {
+ result := new(PublicIp)
+ url := createUrl(api, publicIpPathSegment, ip_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /public_ips/{id}
+func (api *API) UpdatePublicIp(ip_id string, reverse_dns string) (*PublicIp, error) {
+ result := new(PublicIp)
+ url := createUrl(api, publicIpPathSegment, ip_id)
+ req := struct {
+ ReverseDns string `json:"reverse_dns,omitempty"`
+ }{reverse_dns}
+ err := api.Client.Put(url, &req, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+func (ip *PublicIp) GetState() (string, error) {
+ in, err := ip.api.GetPublicIp(ip.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/restclient.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/restclient.go
new file mode 100644
index 000000000..b200a1089
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/restclient.go
@@ -0,0 +1,213 @@
+package oneandone
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ p_url "net/url"
+ "time"
+)
+
+type restClient struct {
+ token string
+}
+
+func newRestClient(token string) *restClient {
+ restClient := new(restClient)
+ restClient.token = token
+ return restClient
+}
+
+func (c *restClient) Get(url string, result interface{}, expectedStatus int) error {
+ return c.doRequest(url, "GET", nil, result, expectedStatus)
+}
+
+func (c *restClient) Delete(url string, requestBody interface{}, result interface{}, expectedStatus int) error {
+ return c.doRequest(url, "DELETE", requestBody, result, expectedStatus)
+}
+
+func (c *restClient) Post(url string, requestBody interface{}, result interface{}, expectedStatus int) error {
+ return c.doRequest(url, "POST", requestBody, result, expectedStatus)
+}
+
+func (c *restClient) Put(url string, requestBody interface{}, result interface{}, expectedStatus int) error {
+ return c.doRequest(url, "PUT", requestBody, result, expectedStatus)
+}
+
+func (c *restClient) doRequest(url string, method string, requestBody interface{}, result interface{}, expectedStatus int) error {
+ var bodyData io.Reader
+ if requestBody != nil {
+ data, _ := json.Marshal(requestBody)
+ bodyData = bytes.NewBuffer(data)
+ }
+
+ request, err := http.NewRequest(method, url, bodyData)
+ if err != nil {
+ return err
+ }
+
+ request.Header.Add("X-Token", c.token)
+ request.Header.Add("Content-Type", "application/json")
+ client := http.Client{}
+ response, err := client.Do(request)
+ if err = isError(response, expectedStatus, err); err != nil {
+ return err
+ }
+
+ defer response.Body.Close()
+ body, err := ioutil.ReadAll(response.Body)
+ if err != nil {
+ return err
+ }
+ return c.unmarshal(body, result)
+}
+
+func (c *restClient) unmarshal(data []byte, result interface{}) error {
+ err := json.Unmarshal(data, result)
+ if err != nil {
+ // handle the case when the result is an empty array instead of an object
+ switch err.(type) {
+ case *json.UnmarshalTypeError:
+ var ra []interface{}
+ e := json.Unmarshal(data, &ra)
+ if e != nil {
+ return e
+ } else if len(ra) > 0 {
+ return err
+ }
+ return nil
+ default:
+ return err
+ }
+ }
+
+ return nil
+}
+
+func isError(response *http.Response, expectedStatus int, err error) error {
+ if err != nil {
+ return err
+ }
+ if response != nil {
+ if response.StatusCode == expectedStatus {
+ // we got a response with the expected HTTP status code, hence no error
+ return nil
+ }
+ body, _ := ioutil.ReadAll(response.Body)
+ // extract the API's error message to be returned later
+ er_resp := new(errorResponse)
+ err = json.Unmarshal(body, er_resp)
+ if err != nil {
+ return err
+ }
+
+ return apiError{response.StatusCode, fmt.Sprintf("Type: %s; Message: %s", er_resp.Type, er_resp.Message)}
+ }
+ return errors.New("Generic error - no response from the REST API service.")
+}
+
+func createUrl(api *API, sections ...interface{}) string {
+ url := api.Endpoint
+ for _, section := range sections {
+ url += "/" + fmt.Sprint(section)
+ }
+ return url
+}
+
+func makeParameterMap(args ...interface{}) (map[string]interface{}, error) {
+ qps := make(map[string]interface{}, len(args))
+ var is_true bool
+ var page, per_page int
+ var sort, query, fields string
+
+ for i, p := range args {
+ switch i {
+ case 0:
+ page, is_true = p.(int)
+ if !is_true {
+ return nil, errors.New("1st parameter must be a page number (integer).")
+ } else if page > 0 {
+ qps["page"] = page
+ }
+ case 1:
+ per_page, is_true = p.(int)
+ if !is_true {
+ return nil, errors.New("2nd parameter must be a per_page number (integer).")
+ } else if per_page > 0 {
+ qps["per_page"] = per_page
+ }
+ case 2:
+ sort, is_true = p.(string)
+ if !is_true {
+ return nil, errors.New("3rd parameter must be a sorting property string (e.g. 'name' or '-name').")
+ } else if sort != "" {
+ qps["sort"] = sort
+ }
+ case 3:
+ query, is_true = p.(string)
+ if !is_true {
+ return nil, errors.New("4th parameter must be a query string to look for the response.")
+ } else if query != "" {
+ qps["q"] = query
+ }
+ case 4:
+ fields, is_true = p.(string)
+ if !is_true {
+ return nil, errors.New("5th parameter must be fields properties string (e.g. 'id,name').")
+ } else if fields != "" {
+ qps["fields"] = fields
+ }
+ default:
+ return nil, errors.New("Wrong number of parameters.")
+ }
+ }
+ return qps, nil
+}
+
+func processQueryParams(url string, args ...interface{}) (string, error) {
+ if len(args) > 0 {
+ params, err := makeParameterMap(args...)
+ if err != nil {
+ return "", err
+ }
+ url = appendQueryParams(url, params)
+ }
+ return url, nil
+}
+
+func processQueryParamsExt(url string, period string, sd *time.Time, ed *time.Time, args ...interface{}) (string, error) {
+ var qm map[string]interface{}
+ var err error
+ if len(args) > 0 {
+ qm, err = makeParameterMap(args...)
+ if err != nil {
+ return "", err
+ }
+ } else {
+ qm = make(map[string]interface{}, 3)
+ }
+ qm["period"] = period
+ if sd != nil && ed != nil {
+ if sd.After(*ed) {
+ return "", errors.New("Start date cannot be after end date.")
+ }
+ qm["start_date"] = sd.Format(time.RFC3339)
+ qm["end_date"] = ed.Format(time.RFC3339)
+ }
+ url = appendQueryParams(url, qm)
+ return url, nil
+}
+
+func appendQueryParams(url string, params map[string]interface{}) string {
+ queryUrl, _ := p_url.Parse(url)
+ parameters := p_url.Values{}
+ for key, value := range params {
+ parameters.Add(key, fmt.Sprintf("%v", value))
+ }
+ queryUrl.RawQuery = parameters.Encode()
+ return queryUrl.String()
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/roles.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/roles.go
new file mode 100644
index 000000000..e8aa44fee
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/roles.go
@@ -0,0 +1,595 @@
+package oneandone
+
+import "net/http"
+
+type Role struct {
+ Identity
+ descField
+ CreationDate string `json:"creation_date,omitempty"`
+ State string `json:"state,omitempty"`
+ Default *int `json:"default,omitempty"`
+ Permissions *Permissions `json:"permissions,omitempty"`
+ Users []Identity `json:"users,omitempty"`
+ ApiPtr
+}
+
+type Permissions struct {
+ Backups *BackupPerm `json:"backups,omitempty"`
+ Firewalls *FirewallPerm `json:"firewall_policies,omitempty"`
+ Images *ImagePerm `json:"images,omitempty"`
+ Invoice *InvoicePerm `json:"interactive_invoices,omitempty"`
+ IPs *IPPerm `json:"public_ips,omitempty"`
+ LoadBalancers *LoadBalancerPerm `json:"load_balancers,omitempty"`
+ Logs *LogPerm `json:"logs,omitempty"`
+ MonitorCenter *MonitorCenterPerm `json:"monitoring_center,omitempty"`
+ MonitorPolicies *MonitorPolicyPerm `json:"monitoring_policies,omitempty"`
+ PrivateNetworks *PrivateNetworkPerm `json:"private_networks,omitempty"`
+ Roles *RolePerm `json:"roles,omitempty"`
+ Servers *ServerPerm `json:"servers,omitempty"`
+ SharedStorage *SharedStoragePerm `json:"shared_storages,omitempty"`
+ Usages *UsagePerm `json:"usages,omitempty"`
+ Users *UserPerm `json:"users,omitempty"`
+ VPNs *VPNPerm `json:"vpn,omitempty"`
+}
+
+type BackupPerm struct {
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ Show bool `json:"show"`
+}
+
+type FirewallPerm struct {
+ Clone bool `json:"clone"`
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ ManageAttachedServerIPs bool `json:"manage_attached_server_ips"`
+ ManageRules bool `json:"manage_rules"`
+ SetDescription bool `json:"set_description"`
+ SetName bool `json:"set_name"`
+ Show bool `json:"show"`
+}
+
+type ImagePerm struct {
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ DisableAutoCreate bool `json:"disable_automatic_creation"`
+ SetDescription bool `json:"set_description"`
+ SetName bool `json:"set_name"`
+ Show bool `json:"show"`
+}
+
+type InvoicePerm struct {
+ Show bool `json:"show"`
+}
+
+type IPPerm struct {
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ Release bool `json:"release"`
+ SetReverseDNS bool `json:"set_reverse_dns"`
+ Show bool `json:"show"`
+}
+
+type LoadBalancerPerm struct {
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ ManageAttachedServerIPs bool `json:"manage_attached_server_ips"`
+ ManageRules bool `json:"manage_rules"`
+ Modify bool `json:"modify"`
+ SetDescription bool `json:"set_description"`
+ SetName bool `json:"set_name"`
+ Show bool `json:"show"`
+}
+
+type LogPerm struct {
+ Show bool `json:"show"`
+}
+
+type MonitorCenterPerm struct {
+ Show bool `json:"show"`
+}
+
+type MonitorPolicyPerm struct {
+ Clone bool `json:"clone"`
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ ManageAttachedServers bool `json:"manage_attached_servers"`
+ ManagePorts bool `json:"manage_ports"`
+ ManageProcesses bool `json:"manage_processes"`
+ ModifyResources bool `json:"modify_resources"`
+ SetDescription bool `json:"set_description"`
+ SetEmail bool `json:"set_email"`
+ SetName bool `json:"set_name"`
+ Show bool `json:"show"`
+}
+
+type PrivateNetworkPerm struct {
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ ManageAttachedServers bool `json:"manage_attached_servers"`
+ SetDescription bool `json:"set_description"`
+ SetName bool `json:"set_name"`
+ SetNetworkInfo bool `json:"set_network_info"`
+ Show bool `json:"show"`
+}
+
+type RolePerm struct {
+ Clone bool `json:"clone"`
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ ManageUsers bool `json:"manage_users"`
+ Modify bool `json:"modify"`
+ SetDescription bool `json:"set_description"`
+ SetName bool `json:"set_name"`
+ Show bool `json:"show"`
+}
+
+type ServerPerm struct {
+ AccessKVMConsole bool `json:"access_kvm_console"`
+ AssignIP bool `json:"assign_ip"`
+ Clone bool `json:"clone"`
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ ManageDVD bool `json:"manage_dvd"`
+ ManageSnapshot bool `json:"manage_snapshot"`
+ Reinstall bool `json:"reinstall"`
+ Resize bool `json:"resize"`
+ Restart bool `json:"restart"`
+ SetDescription bool `json:"set_description"`
+ SetName bool `json:"set_name"`
+ Show bool `json:"show"`
+ Shutdown bool `json:"shutdown"`
+ Start bool `json:"start"`
+}
+
+type SharedStoragePerm struct {
+ Access bool `json:"access"`
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ ManageAttachedServers bool `json:"manage_attached_servers"`
+ Resize bool `json:"resize"`
+ SetDescription bool `json:"set_description"`
+ SetName bool `json:"set_name"`
+ Show bool `json:"show"`
+}
+
+type UsagePerm struct {
+ Show bool `json:"show"`
+}
+
+type UserPerm struct {
+ ChangeRole bool `json:"change_role"`
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ Disable bool `json:"disable"`
+ Enable bool `json:"enable"`
+ ManageAPI bool `json:"manage_api"`
+ SetDescription bool `json:"set_description"`
+ SetEmail bool `json:"set_email"`
+ SetPassword bool `json:"set_password"`
+ Show bool `json:"show"`
+}
+
+type VPNPerm struct {
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ DownloadFile bool `json:"download_file"`
+ SetDescription bool `json:"set_description"`
+ SetName bool `json:"set_name"`
+ Show bool `json:"show"`
+}
+
+// GET /roles
+func (api *API) ListRoles(args ...interface{}) ([]Role, error) {
+ url, err := processQueryParams(createUrl(api, rolePathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []Role{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for _, role := range result {
+ role.api = api
+ }
+ return result, nil
+}
+
+// POST /roles
+func (api *API) CreateRole(name string) (string, *Role, error) {
+ result := new(Role)
+ url := createUrl(api, rolePathSegment)
+ req := struct {
+ Name string `json:"name"`
+ }{name}
+ err := api.Client.Post(url, &req, &result, http.StatusCreated)
+ if err != nil {
+ return "", nil, err
+ }
+ result.api = api
+ return result.Id, result, nil
+}
+
+// GET /roles/{role_id}
+func (api *API) GetRole(role_id string) (*Role, error) {
+ result := new(Role)
+ url := createUrl(api, rolePathSegment, role_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /roles/{role_id}
+func (api *API) ModifyRole(role_id string, name string, description string, state string) (*Role, error) {
+ result := new(Role)
+ url := createUrl(api, rolePathSegment, role_id)
+ req := struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ State string `json:"state,omitempty"`
+ }{Name: name, Description: description, State: state}
+ err := api.Client.Put(url, &req, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /roles/{role_id}
+func (api *API) DeleteRole(role_id string) (*Role, error) {
+ result := new(Role)
+ url := createUrl(api, rolePathSegment, role_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /roles/{role_id}/permissions
+func (api *API) GetRolePermissions(role_id string) (*Permissions, error) {
+ result := new(Permissions)
+ url := createUrl(api, rolePathSegment, role_id, "permissions")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// PUT /roles/{role_id}/permissions
+func (api *API) ModifyRolePermissions(role_id string, perm *Permissions) (*Role, error) {
+ result := new(Role)
+ url := createUrl(api, rolePathSegment, role_id, "permissions")
+ err := api.Client.Put(url, &perm, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /roles/{role_id}/users
+func (api *API) ListRoleUsers(role_id string) ([]Identity, error) {
+ result := []Identity{}
+ url := createUrl(api, rolePathSegment, role_id, "users")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /roles/{role_id}/users
+func (api *API) AssignRoleUsers(role_id string, user_ids []string) (*Role, error) {
+ result := new(Role)
+ url := createUrl(api, rolePathSegment, role_id, "users")
+ req := struct {
+ Users []string `json:"users"`
+ }{user_ids}
+ err := api.Client.Post(url, &req, &result, http.StatusCreated)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /roles/{role_id}/users/{user_id}
+func (api *API) GetRoleUser(role_id string, user_id string) (*Identity, error) {
+ result := new(Identity)
+ url := createUrl(api, rolePathSegment, role_id, "users", user_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /roles/{role_id}/users/{user_id}
+func (api *API) RemoveRoleUser(role_id string, user_id string) (*Role, error) {
+ result := new(Role)
+ url := createUrl(api, rolePathSegment, role_id, "users", user_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// POST /roles/{role_id}/clone
+func (api *API) CloneRole(role_id string, name string) (*Role, error) {
+ result := new(Role)
+ url := createUrl(api, rolePathSegment, role_id, "clone")
+ req := struct {
+ Name string `json:"name"`
+ }{name}
+ err := api.Client.Post(url, &req, &result, http.StatusCreated)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+func (role *Role) GetState() (string, error) {
+ in, err := role.api.GetRole(role.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
+
+// Sets all backups' permissions
+func (bp *BackupPerm) SetAll(value bool) {
+ bp.Create = value
+ bp.Delete = value
+ bp.Show = value
+}
+
+// Sets all firewall policies' permissions
+func (fp *FirewallPerm) SetAll(value bool) {
+ fp.Clone = value
+ fp.Create = value
+ fp.Delete = value
+ fp.ManageAttachedServerIPs = value
+ fp.ManageRules = value
+ fp.SetDescription = value
+ fp.SetName = value
+ fp.Show = value
+}
+
+// Sets all images' permissions
+func (imp *ImagePerm) SetAll(value bool) {
+ imp.Create = value
+ imp.Delete = value
+ imp.DisableAutoCreate = value
+ imp.SetDescription = value
+ imp.SetName = value
+ imp.Show = value
+}
+
+// Sets all invoice's permissions
+func (inp *InvoicePerm) SetAll(value bool) {
+ inp.Show = value
+}
+
+// Sets all IPs' permissions
+func (ipp *IPPerm) SetAll(value bool) {
+ ipp.Create = value
+ ipp.Delete = value
+ ipp.Release = value
+ ipp.SetReverseDNS = value
+ ipp.Show = value
+}
+
+// Sets all load balancers' permissions
+func (lbp *LoadBalancerPerm) SetAll(value bool) {
+ lbp.Create = value
+ lbp.Delete = value
+ lbp.ManageAttachedServerIPs = value
+ lbp.ManageRules = value
+ lbp.Modify = value
+ lbp.SetDescription = value
+ lbp.SetName = value
+ lbp.Show = value
+}
+
+// Sets all logs' permissions
+func (lp *LogPerm) SetAll(value bool) {
+ lp.Show = value
+}
+
+// Sets all monitoring center's permissions
+func (mcp *MonitorCenterPerm) SetAll(value bool) {
+ mcp.Show = value
+}
+
+// Sets all monitoring policies' permissions
+func (mpp *MonitorPolicyPerm) SetAll(value bool) {
+ mpp.Clone = value
+ mpp.Create = value
+ mpp.Delete = value
+ mpp.ManageAttachedServers = value
+ mpp.ManagePorts = value
+ mpp.ManageProcesses = value
+ mpp.ModifyResources = value
+ mpp.SetDescription = value
+ mpp.SetEmail = value
+ mpp.SetName = value
+ mpp.Show = value
+}
+
+// Sets all private networks' permissions
+func (pnp *PrivateNetworkPerm) SetAll(value bool) {
+ pnp.Create = value
+ pnp.Delete = value
+ pnp.ManageAttachedServers = value
+ pnp.SetDescription = value
+ pnp.SetName = value
+ pnp.SetNetworkInfo = value
+ pnp.Show = value
+}
+
+// Sets all roles' permissions
+func (rp *RolePerm) SetAll(value bool) {
+ rp.Clone = value
+ rp.Create = value
+ rp.Delete = value
+ rp.ManageUsers = value
+ rp.Modify = value
+ rp.SetDescription = value
+ rp.SetName = value
+ rp.Show = value
+}
+
+// Sets all servers' permissions
+func (sp *ServerPerm) SetAll(value bool) {
+ sp.AccessKVMConsole = value
+ sp.AssignIP = value
+ sp.Clone = value
+ sp.Create = value
+ sp.Delete = value
+ sp.ManageDVD = value
+ sp.ManageSnapshot = value
+ sp.Reinstall = value
+ sp.Resize = value
+ sp.Restart = value
+ sp.SetDescription = value
+ sp.SetName = value
+ sp.Show = value
+ sp.Shutdown = value
+ sp.Start = value
+}
+
+// Sets all shared storages' permissions
+func (ssp *SharedStoragePerm) SetAll(value bool) {
+ ssp.Access = value
+ ssp.Create = value
+ ssp.Delete = value
+ ssp.ManageAttachedServers = value
+ ssp.Resize = value
+ ssp.SetDescription = value
+ ssp.SetName = value
+ ssp.Show = value
+}
+
+// Sets all usages' permissions
+func (up *UsagePerm) SetAll(value bool) {
+ up.Show = value
+}
+
+// Sets all users' permissions
+func (up *UserPerm) SetAll(value bool) {
+ up.ChangeRole = value
+ up.Create = value
+ up.Delete = value
+ up.Disable = value
+ up.Enable = value
+ up.ManageAPI = value
+ up.SetDescription = value
+ up.SetEmail = value
+ up.SetPassword = value
+ up.Show = value
+}
+
+// Sets all VPNs' permissions
+func (vpnp *VPNPerm) SetAll(value bool) {
+ vpnp.Create = value
+ vpnp.Delete = value
+ vpnp.DownloadFile = value
+ vpnp.SetDescription = value
+ vpnp.SetName = value
+ vpnp.Show = value
+}
+
+// Sets all available permissions
+func (p *Permissions) SetAll(v bool) {
+ if p.Backups == nil {
+ p.Backups = &BackupPerm{v, v, v}
+ } else {
+ p.Backups.SetAll(v)
+ }
+ if p.Firewalls == nil {
+ p.Firewalls = &FirewallPerm{v, v, v, v, v, v, v, v}
+ } else {
+ p.Firewalls.SetAll(v)
+ }
+ if p.Images == nil {
+ p.Images = &ImagePerm{v, v, v, v, v, v}
+ } else {
+ p.Images.SetAll(v)
+ }
+ if p.Invoice == nil {
+ p.Invoice = &InvoicePerm{v}
+ } else {
+ p.Invoice.SetAll(v)
+ }
+ if p.IPs == nil {
+ p.IPs = &IPPerm{v, v, v, v, v}
+ } else {
+ p.IPs.SetAll(v)
+ }
+ if p.LoadBalancers == nil {
+ p.LoadBalancers = &LoadBalancerPerm{v, v, v, v, v, v, v, v}
+ } else {
+ p.LoadBalancers.SetAll(v)
+ }
+ if p.Logs == nil {
+ p.Logs = &LogPerm{v}
+ } else {
+ p.Logs.SetAll(v)
+ }
+ if p.MonitorCenter == nil {
+ p.MonitorCenter = &MonitorCenterPerm{v}
+ } else {
+ p.MonitorCenter.SetAll(v)
+ }
+ if p.MonitorPolicies == nil {
+ p.MonitorPolicies = &MonitorPolicyPerm{v, v, v, v, v, v, v, v, v, v, v}
+ } else {
+ p.MonitorPolicies.SetAll(v)
+ }
+ if p.PrivateNetworks == nil {
+ p.PrivateNetworks = &PrivateNetworkPerm{v, v, v, v, v, v, v}
+ } else {
+ p.PrivateNetworks.SetAll(v)
+ }
+ if p.Roles == nil {
+ p.Roles = &RolePerm{v, v, v, v, v, v, v, v}
+ } else {
+ p.Roles.SetAll(v)
+ }
+ if p.Servers == nil {
+ p.Servers = &ServerPerm{v, v, v, v, v, v, v, v, v, v, v, v, v, v, v}
+ } else {
+ p.Servers.SetAll(v)
+ }
+ if p.SharedStorage == nil {
+ p.SharedStorage = &SharedStoragePerm{v, v, v, v, v, v, v, v}
+ } else {
+ p.SharedStorage.SetAll(v)
+ }
+ if p.Usages == nil {
+ p.Usages = &UsagePerm{v}
+ } else {
+ p.Usages.SetAll(v)
+ }
+ if p.Users == nil {
+ p.Users = &UserPerm{v, v, v, v, v, v, v, v, v, v}
+ } else {
+ p.Users.SetAll(v)
+ }
+ if p.VPNs == nil {
+ p.VPNs = &VPNPerm{v, v, v, v, v, v}
+ } else {
+ p.VPNs.SetAll(v)
+ }
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/serverappliances.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/serverappliances.go
new file mode 100644
index 000000000..03c45f3d8
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/serverappliances.go
@@ -0,0 +1,48 @@
+package oneandone
+
+import "net/http"
+
+type ServerAppliance struct {
+ Identity
+ typeField
+ OsInstallBase string `json:"os_installation_base,omitempty"`
+ OsFamily string `json:"os_family,omitempty"`
+ Os string `json:"os,omitempty"`
+ OsVersion string `json:"os_version,omitempty"`
+ Version string `json:"version,omitempty"`
+ MinHddSize int `json:"min_hdd_size"`
+ Architecture interface{} `json:"os_architecture"`
+ Licenses interface{} `json:"licenses,omitempty"`
+ Categories []string `json:"categories,omitempty"`
+ // AvailableDatacenters []string `json:"available_datacenters,omitempty"`
+ ApiPtr
+}
+
+// GET /server_appliances
+func (api *API) ListServerAppliances(args ...interface{}) ([]ServerAppliance, error) {
+ url, err := processQueryParams(createUrl(api, serverAppliancePathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ res := []ServerAppliance{}
+ err = api.Client.Get(url, &res, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range res {
+ res[index].api = api
+ }
+ return res, nil
+}
+
+// GET /server_appliances/{id}
+func (api *API) GetServerAppliance(sa_id string) (*ServerAppliance, error) {
+ res := new(ServerAppliance)
+ url := createUrl(api, serverAppliancePathSegment, sa_id)
+ err := api.Client.Get(url, &res, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ // res.api = api
+ return res, nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/servers.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/servers.go
new file mode 100644
index 000000000..18fad51a2
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/servers.go
@@ -0,0 +1,808 @@
+package oneandone
+
+import (
+ "encoding/json"
+ "errors"
+ "math/big"
+ "net/http"
+)
+
+type Server struct {
+ ApiPtr
+ Identity
+ descField
+ CloudPanelId string `json:"cloudpanel_id,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ FirstPassword string `json:"first_password,omitempty"`
+ Datacenter *Datacenter `json:"datacenter,omitempty"`
+ Status *Status `json:"status,omitempty"`
+ Hardware *Hardware `json:"hardware,omitempty"`
+ Image *Identity `json:"image,omitempty"`
+ Dvd *Identity `json:"dvd,omitempty"`
+ MonPolicy *Identity `json:"monitoring_policy,omitempty"`
+ Snapshot *ServerSnapshot `json:"snapshot,omitempty"`
+ Ips []ServerIp `json:"ips,omitempty"`
+ PrivateNets []Identity `json:"private_networks,omitempty"`
+ Alerts *ServerAlerts `json:"-"`
+ AlertsRaw *json.RawMessage `json:"alerts,omitempty"`
+}
+
+type Hardware struct {
+ Vcores int `json:"vcore,omitempty"`
+ CoresPerProcessor int `json:"cores_per_processor"`
+ Ram float32 `json:"ram"`
+ Hdds []Hdd `json:"hdds,omitempty"`
+ FixedInsSizeId string `json:"fixed_instance_size_id,omitempty"`
+ ApiPtr
+}
+
+type ServerHdds struct {
+ Hdds []Hdd `json:"hdds,omitempty"`
+}
+
+type Hdd struct {
+ idField
+ Size int `json:"size,omitempty"`
+ IsMain bool `json:"is_main,omitempty"`
+ ApiPtr
+}
+
+type serverDeployImage struct {
+ idField
+ Password string `json:"password,omitempty"`
+ Firewall *Identity `json:"firewall_policy,omitempty"`
+}
+
+type ServerIp struct {
+ idField
+ typeField
+ Ip string `json:"ip,omitempty"`
+ ReverseDns string `json:"reverse_dns,omitempty"`
+ Firewall *Identity `json:"firewall_policy,omitempty"`
+ LoadBalancers []Identity `json:"load_balancers,omitempty"`
+ ApiPtr
+}
+
+type ServerIpInfo struct {
+ idField // IP id
+ Ip string `json:"ip,omitempty"`
+ ServerName string `json:"server_name,omitempty"`
+}
+
+type ServerSnapshot struct {
+ idField
+ CreationDate string `json:"creation_date,omitempty"`
+ DeletionDate string `json:"deletion_date,omitempty"`
+}
+
+type ServerAlerts struct {
+ AlertSummary []serverAlertSummary
+ AlertDetails *serverAlertDetails
+}
+
+type serverAlertSummary struct {
+ countField
+ typeField
+}
+
+type serverAlertDetails struct {
+ Criticals []ServerAlert `json:"critical,omitempty"`
+ Warnings []ServerAlert `json:"warning,omitempty"`
+}
+
+type ServerAlert struct {
+ typeField
+ descField
+ Date string `json:"date"`
+}
+
+type ServerRequest struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ Hardware Hardware `json:"hardware"`
+ ApplianceId string `json:"appliance_id,omitempty"`
+ Password string `json:"password,omitempty"`
+ PowerOn bool `json:"power_on"`
+ FirewallPolicyId string `json:"firewall_policy_id,omitempty"`
+ IpId string `json:"ip_id,omitempty"`
+ LoadBalancerId string `json:"load_balancer_id,omitempty"`
+ MonitoringPolicyId string `json:"monitoring_policy_id,omitempty"`
+ DatacenterId string `json:"datacenter_id,omitempty"`
+ SSHKey string `json:"rsa_key,omitempty"`
+}
+
+type ServerAction struct {
+ Action string `json:"action,omitempty"`
+ Method string `json:"method,omitempty"`
+}
+
+type FixedInstanceInfo struct {
+ Identity
+ Hardware *Hardware `json:"hardware,omitempty"`
+ ApiPtr
+}
+
+// GET /servers
+func (api *API) ListServers(args ...interface{}) ([]Server, error) {
+ url, err := processQueryParams(createUrl(api, serverPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []Server{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for _, s := range result {
+ s.api = api
+ s.decodeRaws()
+ }
+ return result, nil
+}
+
+// POST /servers
+func (api *API) CreateServer(request *ServerRequest) (string, *Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment)
+ insert2map := func(hasht map[string]interface{}, key string, value string) {
+ if key != "" && value != "" {
+ hasht[key] = value
+ }
+ }
+ req := make(map[string]interface{})
+ hw := make(map[string]interface{})
+ req["name"] = request.Name
+ req["description"] = request.Description
+ req["appliance_id"] = request.ApplianceId
+ req["power_on"] = request.PowerOn
+ insert2map(req, "password", request.Password)
+ insert2map(req, "firewall_policy_id", request.FirewallPolicyId)
+ insert2map(req, "ip_id", request.IpId)
+ insert2map(req, "load_balancer_id", request.LoadBalancerId)
+ insert2map(req, "monitoring_policy_id", request.MonitoringPolicyId)
+ insert2map(req, "datacenter_id", request.DatacenterId)
+ insert2map(req, "rsa_key", request.SSHKey)
+ req["hardware"] = hw
+ if request.Hardware.FixedInsSizeId != "" {
+ hw["fixed_instance_size_id"] = request.Hardware.FixedInsSizeId
+ } else {
+ hw["vcore"] = request.Hardware.Vcores
+ hw["cores_per_processor"] = request.Hardware.CoresPerProcessor
+ hw["ram"] = request.Hardware.Ram
+ hw["hdds"] = request.Hardware.Hdds
+ }
+ err := api.Client.Post(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return "", nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result.Id, result, nil
+}
+
+// This is a wraper function for `CreateServer` that returns the server's IP address and first password.
+// The function waits at most `timeout` seconds for the server to be created.
+// The initial `POST /servers` response does not contain the IP address, so we need to wait
+// until the server is created.
+func (api *API) CreateServerEx(request *ServerRequest, timeout int) (string, string, error) {
+ id, server, err := api.CreateServer(request)
+ if server != nil && err == nil {
+ count := timeout / 5
+ if request.PowerOn {
+ err = api.WaitForState(server, "POWERED_ON", 5, count)
+ } else {
+ err = api.WaitForState(server, "POWERED_OFF", 5, count)
+ }
+ if err != nil {
+ return "", "", err
+ }
+ server, err := api.GetServer(id)
+ if server != nil && err == nil && server.Ips[0].Ip != "" {
+ if server.FirstPassword != "" {
+ return server.Ips[0].Ip, server.FirstPassword, nil
+ }
+ if request.Password != "" {
+ return server.Ips[0].Ip, request.Password, nil
+ }
+ // should never reach here
+ return "", "", errors.New("No server's password was found.")
+ }
+ }
+ return "", "", err
+}
+
+// GET /servers/{id}
+func (api *API) GetServer(server_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/fixed_instance_sizes
+func (api *API) ListFixedInstanceSizes() ([]FixedInstanceInfo, error) {
+ result := []FixedInstanceInfo{}
+ url := createUrl(api, serverPathSegment, "fixed_instance_sizes")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// GET /servers/fixed_instance_sizes/{fixed_instance_size_id}
+func (api *API) GetFixedInstanceSize(fis_id string) (*FixedInstanceInfo, error) {
+ result := new(FixedInstanceInfo)
+ url := createUrl(api, serverPathSegment, "fixed_instance_sizes", fis_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /servers/{id}
+func (api *API) DeleteServer(server_id string, keep_ips bool) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id)
+ pm := make(map[string]interface{}, 1)
+ pm["keep_ips"] = keep_ips
+ url = appendQueryParams(url, pm)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// PUT /servers/{id}
+func (api *API) RenameServer(server_id string, new_name string, new_desc string) (*Server, error) {
+ data := struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ }{Name: new_name, Description: new_desc}
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id)
+ err := api.Client.Put(url, &data, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{server_id}/hardware
+func (api *API) GetServerHardware(server_id string) (*Hardware, error) {
+ result := new(Hardware)
+ url := createUrl(api, serverPathSegment, server_id, "hardware")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /servers/{server_id}/hardware
+func (api *API) UpdateServerHardware(server_id string, hardware *Hardware) (*Server, error) {
+ var vc, cpp *int
+ var ram *float32
+ if hardware.Vcores > 0 {
+ vc = new(int)
+ *vc = hardware.Vcores
+ }
+ if hardware.CoresPerProcessor > 0 {
+ cpp = new(int)
+ *cpp = hardware.CoresPerProcessor
+ }
+ if big.NewFloat(float64(hardware.Ram)).Cmp(big.NewFloat(0)) != 0 {
+ ram = new(float32)
+ *ram = hardware.Ram
+ }
+ req := struct {
+ VCores *int `json:"vcore,omitempty"`
+ Cpp *int `json:"cores_per_processor,omitempty"`
+ Ram *float32 `json:"ram,omitempty"`
+ Flavor string `json:"fixed_instance_size_id,omitempty"`
+ }{VCores: vc, Cpp: cpp, Ram: ram, Flavor: hardware.FixedInsSizeId}
+
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "hardware")
+ err := api.Client.Put(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/hardware/hdds
+func (api *API) ListServerHdds(server_id string) ([]Hdd, error) {
+ result := []Hdd{}
+ url := createUrl(api, serverPathSegment, server_id, "hardware/hdds")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /servers/{id}/hardware/hdds
+func (api *API) AddServerHdds(server_id string, hdds *ServerHdds) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "hardware/hdds")
+ err := api.Client.Post(url, &hdds, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/hardware/hdds/{id}
+func (api *API) GetServerHdd(server_id string, hdd_id string) (*Hdd, error) {
+ result := new(Hdd)
+ url := createUrl(api, serverPathSegment, server_id, "hardware/hdds", hdd_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /servers/{id}/hardware/hdds/{id}
+func (api *API) DeleteServerHdd(server_id string, hdd_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "hardware/hdds", hdd_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// PUT /servers/{id}/hardware/hdds/{id}
+func (api *API) ResizeServerHdd(server_id string, hdd_id string, new_size int) (*Server, error) {
+ data := Hdd{Size: new_size}
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "hardware/hdds", hdd_id)
+ err := api.Client.Put(url, &data, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/image
+func (api *API) GetServerImage(server_id string) (*Identity, error) {
+ result := new(Identity)
+ url := createUrl(api, serverPathSegment, server_id, "image")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// PUT /servers/{id}/image
+func (api *API) ReinstallServerImage(server_id string, image_id string, password string, fp_id string) (*Server, error) {
+ data := new(serverDeployImage)
+ data.Id = image_id
+ data.Password = password
+ if fp_id != "" {
+ fp := new(Identity)
+ fp.Id = fp_id
+ data.Firewall = fp
+ }
+
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "image")
+ err := api.Client.Put(url, &data, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/ips
+func (api *API) ListServerIps(server_id string) ([]ServerIp, error) {
+ result := []ServerIp{}
+ url := createUrl(api, serverPathSegment, server_id, "ips")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /servers/{id}/ips
+func (api *API) AssignServerIp(server_id string, ip_type string) (*Server, error) {
+ data := typeField{Type: ip_type}
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "ips")
+ err := api.Client.Post(url, &data, &result, http.StatusCreated)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/ips/{id}
+func (api *API) GetServerIp(server_id string, ip_id string) (*ServerIp, error) {
+ result := new(ServerIp)
+ url := createUrl(api, serverPathSegment, server_id, "ips", ip_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /servers/{id}/ips/{id}
+func (api *API) DeleteServerIp(server_id string, ip_id string, keep_ip bool) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "ips", ip_id)
+ qm := make(map[string]interface{}, 1)
+ qm["keep_ip"] = keep_ip
+ url = appendQueryParams(url, qm)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /servers/{id}/status
+func (api *API) GetServerStatus(server_id string) (*Status, error) {
+ result := new(Status)
+ url := createUrl(api, serverPathSegment, server_id, "status")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// PUT /servers/{id}/status/action (action = REBOOT)
+func (api *API) RebootServer(server_id string, is_hardware bool) (*Server, error) {
+ result := new(Server)
+ request := ServerAction{}
+ request.Action = "REBOOT"
+ if is_hardware {
+ request.Method = "HARDWARE"
+ } else {
+ request.Method = "SOFTWARE"
+ }
+ url := createUrl(api, serverPathSegment, server_id, "status", "action")
+ err := api.Client.Put(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// PUT /servers/{id}/status/action (action = POWER_OFF)
+func (api *API) ShutdownServer(server_id string, is_hardware bool) (*Server, error) {
+ result := new(Server)
+ request := ServerAction{}
+ request.Action = "POWER_OFF"
+ if is_hardware {
+ request.Method = "HARDWARE"
+ } else {
+ request.Method = "SOFTWARE"
+ }
+ url := createUrl(api, serverPathSegment, server_id, "status", "action")
+ err := api.Client.Put(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// PUT /servers/{id}/status/action (action = POWER_ON)
+func (api *API) StartServer(server_id string) (*Server, error) {
+ result := new(Server)
+ request := ServerAction{}
+ request.Action = "POWER_ON"
+ url := createUrl(api, serverPathSegment, server_id, "status", "action")
+ err := api.Client.Put(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/dvd
+func (api *API) GetServerDvd(server_id string) (*Identity, error) {
+ result := new(Identity)
+ url := createUrl(api, serverPathSegment, server_id, "dvd")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /servers/{id}/dvd
+func (api *API) EjectServerDvd(server_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "dvd")
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// PUT /servers/{id}/dvd
+func (api *API) LoadServerDvd(server_id string, dvd_id string) (*Server, error) {
+ request := Identity{}
+ request.Id = dvd_id
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "dvd")
+ err := api.Client.Put(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/private_networks
+func (api *API) ListServerPrivateNetworks(server_id string) ([]Identity, error) {
+ result := []Identity{}
+ url := createUrl(api, serverPathSegment, server_id, "private_networks")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /servers/{id}/private_networks
+func (api *API) AssignServerPrivateNetwork(server_id string, pn_id string) (*Server, error) {
+ req := new(Identity)
+ req.Id = pn_id
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "private_networks")
+ err := api.Client.Post(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/private_networks/{id}
+func (api *API) GetServerPrivateNetwork(server_id string, pn_id string) (*PrivateNetwork, error) {
+ result := new(PrivateNetwork)
+ url := createUrl(api, serverPathSegment, server_id, "private_networks", pn_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /servers/{id}/private_networks/{id}
+func (api *API) RemoveServerPrivateNetwork(server_id string, pn_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "private_networks", pn_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{server_id}/ips/{ip_id}/load_balancers
+func (api *API) ListServerIpLoadBalancers(server_id string, ip_id string) ([]Identity, error) {
+ result := []Identity{}
+ url := createUrl(api, serverPathSegment, server_id, "ips", ip_id, "load_balancers")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /servers/{server_id}/ips/{ip_id}/load_balancers
+func (api *API) AssignServerIpLoadBalancer(server_id string, ip_id string, lb_id string) (*Server, error) {
+ req := struct {
+ LbId string `json:"load_balancer_id"`
+ }{lb_id}
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "ips", ip_id, "load_balancers")
+ err := api.Client.Post(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// DELETE /servers/{server_id}/ips/{ip_id}/load_balancers
+func (api *API) UnassignServerIpLoadBalancer(server_id string, ip_id string, lb_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "ips", ip_id, "load_balancers", lb_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{server_id}/ips/{ip_id}/firewall_policy
+func (api *API) GetServerIpFirewallPolicy(server_id string, ip_id string) (*Identity, error) {
+ result := new(Identity)
+ url := createUrl(api, serverPathSegment, server_id, "ips", ip_id, "firewall_policy")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// PUT /servers/{server_id}/ips/{ip_id}/firewall_policy
+func (api *API) AssignServerIpFirewallPolicy(server_id string, ip_id string, fp_id string) (*Server, error) {
+ req := idField{fp_id}
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "ips", ip_id, "firewall_policy")
+ err := api.Client.Put(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// DELETE /servers/{server_id}/ips/{ip_id}/firewall_policy
+func (api *API) UnassignServerIpFirewallPolicy(server_id string, ip_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "ips", ip_id, "firewall_policy")
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// GET /servers/{id}/snapshots
+func (api *API) GetServerSnapshot(server_id string) (*ServerSnapshot, error) {
+ result := new(ServerSnapshot)
+ url := createUrl(api, serverPathSegment, server_id, "snapshots")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /servers/{id}/snapshots
+func (api *API) CreateServerSnapshot(server_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "snapshots")
+ err := api.Client.Post(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// PUT /servers/{server_id}/snapshots/{snapshot_id}
+func (api *API) RestoreServerSnapshot(server_id string, snapshot_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "snapshots", snapshot_id)
+ err := api.Client.Put(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// DELETE /servers/{server_id}/snapshots/{snapshot_id}
+func (api *API) DeleteServerSnapshot(server_id string, snapshot_id string) (*Server, error) {
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "snapshots", snapshot_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+// POST /servers/{server_id}/clone
+func (api *API) CloneServer(server_id string, new_name string, datacenter_id string) (*Server, error) {
+ data := struct {
+ Name string `json:"name"`
+ DatacenterId string `json:"datacenter_id,omitempty"`
+ }{Name: new_name, DatacenterId: datacenter_id}
+ result := new(Server)
+ url := createUrl(api, serverPathSegment, server_id, "clone")
+ err := api.Client.Post(url, &data, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ result.decodeRaws()
+ return result, nil
+}
+
+func (s *Server) GetState() (string, error) {
+ st, err := s.api.GetServerStatus(s.Id)
+ if st == nil {
+ return "", err
+ }
+ return st.State, err
+}
+
+func (server *Server) decodeRaws() {
+ if server.AlertsRaw != nil {
+ server.Alerts = new(ServerAlerts)
+ var sad serverAlertDetails
+ if err := json.Unmarshal(*server.AlertsRaw, &sad); err == nil {
+ server.Alerts.AlertDetails = &sad
+ return
+ }
+ var sams []serverAlertSummary
+ if err := json.Unmarshal(*server.AlertsRaw, &sams); err == nil {
+ server.Alerts.AlertSummary = sams
+ }
+ }
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/setup.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/setup.go
new file mode 100644
index 000000000..7d910c653
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/setup.go
@@ -0,0 +1,19 @@
+package oneandone
+
+// The base url for 1&1 Cloud Server REST API.
+var BaseUrl = "https://cloudpanel-api.1and1.com/v1"
+
+// Authentication token
+var Token string
+
+// SetBaseUrl is intended to set the REST base url. BaseUrl is declared in setup.go
+func SetBaseUrl(newbaseurl string) string {
+ BaseUrl = newbaseurl
+ return BaseUrl
+}
+
+// SetToken is used to set authentication Token for the REST service. Token is declared in setup.go
+func SetToken(newtoken string) string {
+ Token = newtoken
+ return Token
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/sharedstorages.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/sharedstorages.go
new file mode 100644
index 000000000..fdb2a7bfd
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/sharedstorages.go
@@ -0,0 +1,190 @@
+package oneandone
+
+import (
+ "net/http"
+)
+
+type SharedStorage struct {
+ Identity
+ descField
+ Size int `json:"size"`
+ MinSizeAllowed int `json:"minimum_size_allowed"`
+ SizeUsed string `json:"size_used,omitempty"`
+ State string `json:"state,omitempty"`
+ CloudPanelId string `json:"cloudpanel_id,omitempty"`
+ SiteId string `json:"site_id,omitempty"`
+ CifsPath string `json:"cifs_path,omitempty"`
+ NfsPath string `json:"nfs_path,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ Servers []SharedStorageServer `json:"servers,omitempty"`
+ Datacenter *Datacenter `json:"datacenter,omitempty"`
+ ApiPtr
+}
+
+type SharedStorageServer struct {
+ Id string `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+ Rights string `json:"rights,omitempty"`
+}
+
+type SharedStorageRequest struct {
+ DatacenterId string `json:"datacenter_id,omitempty"`
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ Size *int `json:"size"`
+}
+
+type SharedStorageAccess struct {
+ State string `json:"state,omitempty"`
+ KerberosContentFile string `json:"kerberos_content_file,omitempty"`
+ UserDomain string `json:"user_domain,omitempty"`
+ SiteId string `json:"site_id,omitempty"`
+ NeedsPasswordReset int `json:"needs_password_reset"`
+}
+
+// GET /shared_storages
+func (api *API) ListSharedStorages(args ...interface{}) ([]SharedStorage, error) {
+ url, err := processQueryParams(createUrl(api, sharedStoragePathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []SharedStorage{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /shared_storages
+func (api *API) CreateSharedStorage(request *SharedStorageRequest) (string, *SharedStorage, error) {
+ result := new(SharedStorage)
+ url := createUrl(api, sharedStoragePathSegment)
+ err := api.Client.Post(url, request, &result, http.StatusAccepted)
+ if err != nil {
+ return "", nil, err
+ }
+ result.api = api
+ return result.Id, result, nil
+}
+
+// GET /shared_storages/{id}
+func (api *API) GetSharedStorage(ss_id string) (*SharedStorage, error) {
+ result := new(SharedStorage)
+ url := createUrl(api, sharedStoragePathSegment, ss_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /shared_storages/{id}
+func (api *API) DeleteSharedStorage(ss_id string) (*SharedStorage, error) {
+ result := new(SharedStorage)
+ url := createUrl(api, sharedStoragePathSegment, ss_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /shared_storages/{id}
+func (api *API) UpdateSharedStorage(ss_id string, request *SharedStorageRequest) (*SharedStorage, error) {
+ result := new(SharedStorage)
+ url := createUrl(api, sharedStoragePathSegment, ss_id)
+ err := api.Client.Put(url, &request, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /shared_storages/{id}/servers
+func (api *API) ListSharedStorageServers(st_id string) ([]SharedStorageServer, error) {
+ result := []SharedStorageServer{}
+ url := createUrl(api, sharedStoragePathSegment, st_id, "servers")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /shared_storages/{id}/servers
+func (api *API) AddSharedStorageServers(st_id string, servers []SharedStorageServer) (*SharedStorage, error) {
+ result := new(SharedStorage)
+ req := struct {
+ Servers []SharedStorageServer `json:"servers"`
+ }{servers}
+ url := createUrl(api, sharedStoragePathSegment, st_id, "servers")
+ err := api.Client.Post(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /shared_storages/{id}/servers/{id}
+func (api *API) GetSharedStorageServer(st_id string, ser_id string) (*SharedStorageServer, error) {
+ result := new(SharedStorageServer)
+ url := createUrl(api, sharedStoragePathSegment, st_id, "servers", ser_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// DELETE /shared_storages/{id}/servers/{id}
+func (api *API) DeleteSharedStorageServer(st_id string, ser_id string) (*SharedStorage, error) {
+ result := new(SharedStorage)
+ url := createUrl(api, sharedStoragePathSegment, st_id, "servers", ser_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /shared_storages/access
+func (api *API) GetSharedStorageCredentials() ([]SharedStorageAccess, error) {
+ result := []SharedStorageAccess{}
+ url := createUrl(api, sharedStoragePathSegment, "access")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// PUT /shared_storages/access
+func (api *API) UpdateSharedStorageCredentials(new_pass string) ([]SharedStorageAccess, error) {
+ result := []SharedStorageAccess{}
+ req := struct {
+ Password string `json:"password"`
+ }{new_pass}
+ url := createUrl(api, sharedStoragePathSegment, "access")
+ err := api.Client.Put(url, &req, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (ss *SharedStorage) GetState() (string, error) {
+ in, err := ss.api.GetSharedStorage(ss.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/usages.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/usages.go
new file mode 100644
index 000000000..e56c9f2ef
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/usages.go
@@ -0,0 +1,52 @@
+package oneandone
+
+import (
+ "net/http"
+ "time"
+)
+
+type Usages struct {
+ Images []usage `json:"IMAGES,omitempty"`
+ LoadBalancers []usage `json:"LOAD BALANCERS,omitempty"`
+ PublicIPs []usage `json:"PUBLIC IP,omitempty"`
+ Servers []usage `json:"SERVERS,omitempty"`
+ SharedStorages []usage `json:"SHARED STORAGE,omitempty"`
+ ApiPtr
+}
+
+type usage struct {
+ Identity
+ Site int `json:"site"`
+ Services []usageService `json:"services,omitempty"`
+}
+
+type usageService struct {
+ AverageAmmount string `json:"avg_amount,omitempty"`
+ Unit string `json:"unit,omitempty"`
+ Usage int `json:"usage"`
+ Details []usageDetails `json:"detail,omitempty"`
+ typeField
+}
+
+type usageDetails struct {
+ AverageAmmount string `json:"avg_amount,omitempty"`
+ StartDate string `json:"start_date,omitempty"`
+ EndDate string `json:"end_date,omitempty"`
+ Unit string `json:"unit,omitempty"`
+ Usage int `json:"usage,omitempty"`
+}
+
+// GET /usages
+func (api *API) ListUsages(period string, sd *time.Time, ed *time.Time, args ...interface{}) (*Usages, error) {
+ result := new(Usages)
+ url, err := processQueryParamsExt(createUrl(api, usagePathSegment), period, sd, ed, args...)
+ if err != nil {
+ return nil, err
+ }
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/users.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/users.go
new file mode 100644
index 000000000..782d07a50
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/users.go
@@ -0,0 +1,205 @@
+package oneandone
+
+import "net/http"
+
+type User struct {
+ Identity
+ descField
+ CreationDate string `json:"creation_date,omitempty"`
+ Email string `json:"email,omitempty"`
+ State string `json:"state,omitempty"`
+ Role *Identity `json:"role,omitempty"`
+ Api *UserApi `json:"api,omitempty"`
+ ApiPtr
+}
+
+type UserApi struct {
+ Active bool `json:"active"`
+ AllowedIps []string `json:"allowed_ips,omitempty"`
+ UserApiKey
+ ApiPtr
+}
+
+type UserApiKey struct {
+ Key string `json:"key,omitempty"`
+}
+
+type UserRequest struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ Password string `json:"password,omitempty"`
+ Email string `json:"email,omitempty"`
+ State string `json:"state,omitempty"`
+}
+
+// GET /users
+func (api *API) ListUsers(args ...interface{}) ([]User, error) {
+ url, err := processQueryParams(createUrl(api, userPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []User{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for index, _ := range result {
+ result[index].api = api
+ }
+ return result, nil
+}
+
+// POST /users
+func (api *API) CreateUser(user *UserRequest) (string, *User, error) {
+ result := new(User)
+ url := createUrl(api, userPathSegment)
+ err := api.Client.Post(url, &user, &result, http.StatusCreated)
+ if err != nil {
+ return "", nil, err
+ }
+ result.api = api
+ return result.Id, result, nil
+}
+
+// GET /users/{id}
+func (api *API) GetUser(user_id string) (*User, error) {
+ result := new(User)
+ url := createUrl(api, userPathSegment, user_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /users/{id}
+func (api *API) DeleteUser(user_id string) (*User, error) {
+ result := new(User)
+ url := createUrl(api, userPathSegment, user_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /users/{id}
+func (api *API) ModifyUser(user_id string, user *UserRequest) (*User, error) {
+ result := new(User)
+ url := createUrl(api, userPathSegment, user_id)
+ err := api.Client.Put(url, &user, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /users/{id}/api
+func (api *API) GetUserApi(user_id string) (*UserApi, error) {
+ result := new(UserApi)
+ url := createUrl(api, userPathSegment, user_id, "api")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /users/{id}/api
+func (api *API) ModifyUserApi(user_id string, active bool) (*User, error) {
+ result := new(User)
+ req := struct {
+ Active bool `json:"active"`
+ }{active}
+ url := createUrl(api, userPathSegment, user_id, "api")
+ err := api.Client.Put(url, &req, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /users/{id}/api/key
+func (api *API) GetUserApiKey(user_id string) (*UserApiKey, error) {
+ result := new(UserApiKey)
+ url := createUrl(api, userPathSegment, user_id, "api/key")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// PUT /users/{id}/api/key
+func (api *API) RenewUserApiKey(user_id string) (*User, error) {
+ result := new(User)
+ url := createUrl(api, userPathSegment, user_id, "api/key")
+ err := api.Client.Put(url, nil, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /users/{id}/api/ips
+func (api *API) ListUserApiAllowedIps(user_id string) ([]string, error) {
+ result := []string{}
+ url := createUrl(api, userPathSegment, user_id, "api/ips")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+// POST /users/{id}/api/ips
+func (api *API) AddUserApiAlowedIps(user_id string, ips []string) (*User, error) {
+ result := new(User)
+ req := struct {
+ Ips []string `json:"ips"`
+ }{ips}
+ url := createUrl(api, userPathSegment, user_id, "api/ips")
+ err := api.Client.Post(url, &req, &result, http.StatusCreated)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /users/{id}/api/ips/{ip}
+func (api *API) RemoveUserApiAllowedIp(user_id string, ip string) (*User, error) {
+ result := new(User)
+ url := createUrl(api, userPathSegment, user_id, "api/ips", ip)
+ err := api.Client.Delete(url, nil, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /users/{id}/api/ips
+func (api *API) GetCurrentUserPermissions() (*Permissions, error) {
+ result := new(Permissions)
+ url := createUrl(api, userPathSegment, "current_user_permissions")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func (u *User) GetState() (string, error) {
+ in, err := u.api.GetUser(u.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/vpns.go b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/vpns.go
new file mode 100644
index 000000000..723a85459
--- /dev/null
+++ b/vendor/github.com/1and1/oneandone-cloudserver-sdk-go/vpns.go
@@ -0,0 +1,114 @@
+package oneandone
+
+import "net/http"
+
+type VPN struct {
+ Identity
+ descField
+ typeField
+ CloudPanelId string `json:"cloudpanel_id,omitempty"`
+ CreationDate string `json:"creation_date,omitempty"`
+ State string `json:"state,omitempty"`
+ IPs []string `json:"ips,omitempty"`
+ Datacenter *Datacenter `json:"datacenter,omitempty"`
+ ApiPtr
+}
+
+type configZipFile struct {
+ Base64String string `json:"config_zip_file"`
+}
+
+// GET /vpns
+func (api *API) ListVPNs(args ...interface{}) ([]VPN, error) {
+ url, err := processQueryParams(createUrl(api, vpnPathSegment), args...)
+ if err != nil {
+ return nil, err
+ }
+ result := []VPN{}
+ err = api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ for _, vpn := range result {
+ vpn.api = api
+ }
+ return result, nil
+}
+
+// POST /vpns
+func (api *API) CreateVPN(name string, description string, datacenter_id string) (string, *VPN, error) {
+ res := new(VPN)
+ url := createUrl(api, vpnPathSegment)
+ req := struct {
+ Name string `json:"name"`
+ Description string `json:"description,omitempty"`
+ DatacenterId string `json:"datacenter_id,omitempty"`
+ }{Name: name, Description: description, DatacenterId: datacenter_id}
+ err := api.Client.Post(url, &req, &res, http.StatusAccepted)
+ if err != nil {
+ return "", nil, err
+ }
+ res.api = api
+ return res.Id, res, nil
+}
+
+// GET /vpns/{vpn_id}
+func (api *API) GetVPN(vpn_id string) (*VPN, error) {
+ result := new(VPN)
+ url := createUrl(api, vpnPathSegment, vpn_id)
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// PUT /vpns/{vpn_id}
+func (api *API) ModifyVPN(vpn_id string, name string, description string) (*VPN, error) {
+ result := new(VPN)
+ url := createUrl(api, vpnPathSegment, vpn_id)
+ req := struct {
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ }{Name: name, Description: description}
+ err := api.Client.Put(url, &req, &result, http.StatusOK)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// DELETE /vpns/{vpn_id}
+func (api *API) DeleteVPN(vpn_id string) (*VPN, error) {
+ result := new(VPN)
+ url := createUrl(api, vpnPathSegment, vpn_id)
+ err := api.Client.Delete(url, nil, &result, http.StatusAccepted)
+ if err != nil {
+ return nil, err
+ }
+ result.api = api
+ return result, nil
+}
+
+// GET /vpns/{vpn_id}/configuration_file
+// Returns VPN configuration files (in a zip arhive) as a base64 encoded string
+func (api *API) GetVPNConfigFile(vpn_id string) (string, error) {
+ result := new(configZipFile)
+ url := createUrl(api, vpnPathSegment, vpn_id, "configuration_file")
+ err := api.Client.Get(url, &result, http.StatusOK)
+ if err != nil {
+ return "", err
+ }
+
+ return result.Base64String, nil
+}
+
+func (vpn *VPN) GetState() (string, error) {
+ in, err := vpn.api.GetVPN(vpn.Id)
+ if in == nil {
+ return "", err
+ }
+ return in.State, err
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index f56d8a8bf..51052b081 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -14,6 +14,12 @@
"revision": "81b7822b1e798e8f17bf64b59512a5be4097e966",
"revisionTime": "2017-01-18T16:13:56Z"
},
+ {
+ "checksumSHA1": "aABATU51PlDHfGeSe5cc9udwSXg=",
+ "path": "github.com/1and1/oneandone-cloudserver-sdk-go",
+ "revision": "5678f03fc801525df794f953aa82f5ad7555a2ef",
+ "revisionTime": "2016-08-11T22:04:02Z"
+ },
{
"checksumSHA1": "N92Zji40JkCHAnsCNHTP4iKPz88=",
"comment": "v2.1.1-beta-8-gca4d906",
diff --git a/website/source/docs/providers/oneandone/index.html.markdown b/website/source/docs/providers/oneandone/index.html.markdown
new file mode 100644
index 000000000..6a215ee36
--- /dev/null
+++ b/website/source/docs/providers/oneandone/index.html.markdown
@@ -0,0 +1,54 @@
+---
+layout: "oneandone"
+page_title: "Provider: 1&1"
+sidebar_current: "docs-oneandone-index"
+description: |-
+ A provider for 1&1.
+---
+
+# 1&1 Provider
+
+The 1&1 provider gives the ability to deploy and configure resources using the 1&1 Cloud Server API.
+
+Use the navigation to the left to read about the available resources.
+
+
+## Usage
+
+The provider needs to be configured with proper credentials before it can be used.
+
+
+```
+$ export ONEANDONE_TOKEN="oneandone_token"
+```
+
+Or you can provide your credentials like this:
+
+
+The credentials provided in `.tf` file will override credentials in the environment variables.
+
+## Example Usage
+
+
+```
+provider "oneandone"{
+ token = "oneandone_token"
+ endpoint = "oneandone_endpoint"
+ retries = 100
+}
+
+resource "oneandone_server" "server" {
+ # ...
+}
+```
+
+
+## Configuration Reference
+
+The following arguments are supported:
+
+* `token` - (Required) If omitted, the `ONEANDONE_TOKEN` environment variable is used.
+
+* `endpoint` - (Optional)
+
+* `retries` - (Optional) Number of retries while waiting for a resource to be provisioned. Default value is 50.
diff --git a/website/source/docs/providers/oneandone/r/oneandone_firewall_policy.html.markdown b/website/source/docs/providers/oneandone/r/oneandone_firewall_policy.html.markdown
new file mode 100644
index 000000000..594ef7ffa
--- /dev/null
+++ b/website/source/docs/providers/oneandone/r/oneandone_firewall_policy.html.markdown
@@ -0,0 +1,58 @@
+---
+layout: "oneandone"
+page_title: "1&1: oneandone_firewall_policy"
+sidebar_current: "docs-oneandone-resource-firwall-policy"
+description: |-
+ Creates and manages 1&1 Firewall Policy.
+---
+
+# oneandone\_server
+
+Manages a Firewall Policy on 1&1
+
+## Example Usage
+
+```
+resource "oneandone_firewall_policy" "fw" {
+ name = "test_fw_011"
+ rules = [
+ {
+ "protocol" = "TCP"
+ "port_from" = 80
+ "port_to" = 80
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "ICMP"
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "TCP"
+ "port_from" = 43
+ "port_to" = 43
+ "source_ip" = "0.0.0.0"
+ },
+ {
+ "protocol" = "TCP"
+ "port_from" = 22
+ "port_to" = 22
+ "source_ip" = "0.0.0.0"
+ }
+ ]
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `description` - (Optional) [string] Description for the VPN
+* `name` - (Required) [string] The name of the VPN.
+
+Firewall Policy Rules (`rules`) support the follwing:
+
+* `protocol` - (Required) [String] The protocol for the rule ["TCP", "UDP", "TCP/UDP", "ICMP", "IPSEC"]
+* `port_from` - (Optional) [String] Defines the start range of the allowed port
+* `port_to` - (Optional) [String] Defines the end range of the allowed port
+* `source_ip` - (Optional) [String] Only traffic directed to the respective IP address
+
diff --git a/website/source/docs/providers/oneandone/r/oneandone_loadbalancer.html.markdown b/website/source/docs/providers/oneandone/r/oneandone_loadbalancer.html.markdown
new file mode 100644
index 000000000..e77d66169
--- /dev/null
+++ b/website/source/docs/providers/oneandone/r/oneandone_loadbalancer.html.markdown
@@ -0,0 +1,61 @@
+---
+layout: "oneandone"
+page_title: "1&1: oneandone_loadbalancer"
+sidebar_current: "docs-oneandone-resource-loadbalancer"
+description: |-
+ Creates and manages 1&1 Load Balancer.
+---
+
+# oneandone\_server
+
+Manages a Load Balancer on 1&1
+
+## Example Usage
+
+```
+resource "oneandone_loadbalancer" "lb" {
+ name = "test_lb"
+ method = "ROUND_ROBIN"
+ persistence = true
+ persistence_time = 60
+ health_check_test = "TCP"
+ health_check_interval = 300
+ datacenter = "GB"
+ rules = [
+ {
+ protocol = "TCP"
+ port_balancer = 8080
+ port_server = 8089
+ source_ip = "0.0.0.0"
+ },
+ {
+ protocol = "TCP"
+ port_balancer = 9090
+ port_server = 9099
+ source_ip = "0.0.0.0"
+ }
+ ]
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `name` - (Required) [String] The name of the load balancer.
+* `description` - (Optional) [String] Description for the load balancer
+* `method` - (Required) [String] Balancing procedure ["ROUND_ROBIN", "LEAST_CONNECTIONS"]
+* `datacenter` - (Optional) [String] Location of desired 1and1 datacenter ["DE", "GB", "US", "ES" ]
+* `persistence` - (Optional) [Boolean] True/false defines whether persistence should be turned on/off
+* `persistence_time` - (Optional) [Integer] Persistance duration in seconds
+* `health_check_test` - (Optional) [String] ["TCP", "ICMP"]
+* `health_check_test_interval` - (Optional) [String]
+* `health_check_test_path` - (Optional) [String]
+* `health_check_test_parser` - (Optional) [String]
+
+Loadbalancer rules (`rules`) support the following
+
+* `protocol` - (Required) [String] The protocol for the rule ["TCP", "UDP", "TCP/UDP", "ICMP", "IPSEC"]
+* `port_balancer` - (Required) [String]
+* `port_server` - (Required) [String]
+* `source_ip` - (Required) [String]
diff --git a/website/source/docs/providers/oneandone/r/oneandone_monitoring_policy.html.markdown b/website/source/docs/providers/oneandone/r/oneandone_monitoring_policy.html.markdown
new file mode 100644
index 000000000..2e3b6cfa2
--- /dev/null
+++ b/website/source/docs/providers/oneandone/r/oneandone_monitoring_policy.html.markdown
@@ -0,0 +1,177 @@
+---
+layout: "oneandone"
+page_title: "1&1: oneandone_monitoring_policy"
+sidebar_current: "docs-oneandone-resource-monitoring-policy"
+description: |-
+ Creates and manages 1&1 Monitoring Policy.
+---
+
+# oneandone\_server
+
+Manages a Monitoring Policy on 1&1
+
+## Example Usage
+
+```
+resource "oneandone_monitoring_policy" "mp" {
+ name = "test_mp"
+ agent = true
+ email = "jasmin@stackpointcloud.com"
+
+ thresholds = {
+ cpu = {
+ warning = {
+ value = 50,
+ alert = false
+ }
+ critical = {
+ value = 66,
+ alert = false
+ }
+
+ }
+ ram = {
+ warning = {
+ value = 70,
+ alert = true
+ }
+ critical = {
+ value = 80,
+ alert = true
+ }
+ },
+ ram = {
+ warning = {
+ value = 85,
+ alert = true
+ }
+ critical = {
+ value = 95,
+ alert = true
+ }
+ },
+ disk = {
+ warning = {
+ value = 84,
+ alert = true
+ }
+ critical = {
+ value = 94,
+ alert = true
+ }
+ },
+ transfer = {
+ warning = {
+ value = 1000,
+ alert = true
+ }
+ critical = {
+ value = 2000,
+ alert = true
+ }
+ },
+ internal_ping = {
+ warning = {
+ value = 3000,
+ alert = true
+ }
+ critical = {
+ value = 4000,
+ alert = true
+ }
+ }
+ }
+ ports = [
+ {
+ email_notification = true
+ port = 443
+ protocol = "TCP"
+ alert_if = "NOT_RESPONDING"
+ },
+ {
+ email_notification = false
+ port = 80
+ protocol = "TCP"
+ alert_if = "NOT_RESPONDING"
+ },
+ {
+ email_notification = true
+ port = 21
+ protocol = "TCP"
+ alert_if = "NOT_RESPONDING"
+ }
+ ]
+
+ processes = [
+ {
+ email_notification = false
+ process = "httpdeamon"
+ alert_if = "RUNNING"
+ },
+ {
+ process = "iexplorer",
+ alert_if = "NOT_RUNNING"
+ email_notification = true
+ }]
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `name` - (Required) [string] The name of the VPN.
+* `description` - (Optional) [string] Description for the VPN
+* `email` - (Optional) [String] Email address to which notifications monitoring system will send
+* `agent- (Required)[Boolean] Indicates which monitoring type will be used. True: To use this monitoring type, you must install an agent on the server. False: Monitor a server without installing an agent. Note: If you do not install an agent, you cannot retrieve information such as free hard disk space or ongoing processes.
+
+Monitoring Policy Thresholds (`thresholds`) support the following:
+
+* `cpu - (Required)[Type] CPU thresholds
+ * `warning - (Required)[Type] Warning alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+ * `critical - (Required)[Type] Critical alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+* `ram - (Required)[Type] RAM threshold
+ * `warning - (Required)[Type] Warning alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+ * `critical - (Required)[Type] Critical alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+* `disk - (Required)[Type] Hard Disk threshold
+ * `warning - (Required)[Type] Warning alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+ * `critical - (Required)[Type] Critical alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+* `transfer - (Required)[Type] Data transfer threshold
+ * `warning - (Required)[Type] Warning alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+ * `critical - (Required)[Type] Critical alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+* `internal_ping - (Required)[type] Ping threshold
+ * `warning - (Required)[Type] Warning alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+ * `critical - (Required)[Type] Critical alert
+ * `value - (Required)[Integer] Warning to be issued when the threshold is reached. from 1 to 100
+ * `alert - (Required)[Boolean] If set true warning will be issued.
+
+Monitoring Policy Ports (`ports`) support the following:
+
+* `email_notification - (Required)[boolean] If set true email will be sent.
+* `port - (Required)[Integer] Port number.
+* `protocol - (Required)[String] The protocol of the port ["TCP", "UDP", "TCP/UDP", "ICMP", "IPSEC"]
+* `alert_if - (Required)[String] Condition for the alert to be issued.
+
+Monitoring Policy Ports (`processes`) support the following:
+
+* `email_notification - (Required)[Boolean] If set true email will be sent.
+* `process - (Required)[Integer] Process name.
+* `alert_if - (Required)[String] Condition for the alert to be issued.
diff --git a/website/source/docs/providers/oneandone/r/oneandone_private_network.html.markdown b/website/source/docs/providers/oneandone/r/oneandone_private_network.html.markdown
new file mode 100644
index 000000000..0a0456127
--- /dev/null
+++ b/website/source/docs/providers/oneandone/r/oneandone_private_network.html.markdown
@@ -0,0 +1,38 @@
+---
+layout: "oneandone"
+page_title: "1&1: oneandone_private_network"
+sidebar_current: "docs-oneandone-resource-private-network"
+description: |-
+ Creates and manages 1&1 Private Network.
+---
+
+# oneandone\_server
+
+Manages a Private Network on 1&1
+
+## Example Usage
+
+```
+resource "oneandone_private_network" "pn" {
+ name = "pn_test",
+ description = "new stuff001"
+ datacenter = "GB"
+ network_address = "192.168.7.0"
+ subnet_mask = "255.255.255.0"
+ server_ids = [
+ "${oneandone_server.server.id}",
+ "${oneandone_server.server02.id}",
+ ]
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `datacenter` - (Optional)[string] Location of desired 1and1 datacenter ["DE", "GB", "US", "ES" ]
+* `description` - (Optional)[string] Description for the shared storage
+* `name` - (Required)[string] The name of the private network
+* `network_address` - (Optional)[string] Network address for the private network
+* `subnet_mask` - (Optional)[string] Subnet mask for the private network
+* `server_ids` (Optional)[Collection] List of servers that are to be associated with the private network
diff --git a/website/source/docs/providers/oneandone/r/oneandone_public_ip.html.markdown b/website/source/docs/providers/oneandone/r/oneandone_public_ip.html.markdown
new file mode 100644
index 000000000..cb00d222a
--- /dev/null
+++ b/website/source/docs/providers/oneandone/r/oneandone_public_ip.html.markdown
@@ -0,0 +1,29 @@
+---
+layout: "oneandone"
+page_title: "1&1: oneandone_public_ip"
+sidebar_current: "docs-oneandone-resource-public-ip"
+description: |-
+ Creates and manages 1&1 Public IP.
+---
+
+# oneandone\_vpn
+
+Manages a Public IP on 1&1
+
+## Example Usage
+
+```
+resource "oneandone_vpn" "vpn" {
+ datacenter = "GB"
+ name = "test_vpn_01"
+ description = "ttest descr"
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `datacenter` - (Optional)[string] Location of desired 1and1 datacenter ["DE", "GB", "US", "ES" ]
+* `description` - (Optional)[string] Description of the VPN
+* `name` -(Required)[string] The name of the VPN.
diff --git a/website/source/docs/providers/oneandone/r/oneandone_server.html.markdown b/website/source/docs/providers/oneandone/r/oneandone_server.html.markdown
new file mode 100644
index 000000000..7e88b972a
--- /dev/null
+++ b/website/source/docs/providers/oneandone/r/oneandone_server.html.markdown
@@ -0,0 +1,60 @@
+---
+layout: "oneandone"
+page_title: "1&1: oneandone_server"
+sidebar_current: "docs-oneandone-resource-server"
+description: |-
+ Creates and manages 1&1 Server.
+---
+
+# oneandone\_server
+
+Manages a Server on 1&1
+
+## Example Usage
+
+```
+resource "oneandone_server" "server" {
+ name = "Example"
+ description = "Terraform 1and1 tutorial"
+ image = "ubuntu"
+ datacenter = "GB"
+ vcores = 1
+ cores_per_processor = 1
+ ram = 2
+ ssh_key_path = "/path/to/prvate/ssh_key"
+ hdds = [
+ {
+ disk_size = 60
+ is_main = true
+ }
+ ]
+
+ provisioner "remote-exec" {
+ inline = [
+ "apt-get update",
+ "apt-get -y install nginx",
+ ]
+ }
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `cores_per_processor` -(Required)[integer] Number of cores per processor
+* `datacenter` - (Optional)[string] Location of desired 1and1 datacenter ["DE", "GB", "US", "ES" ]
+* `description` - (Optional)[string] Description of the server
+* `firewall_policy_id` - (Optional)[string] ID of firewall policy
+* `hdds` - (Required)[collection] List of HDDs. One HDD must be main.
+* `*disk_size` -(Required)[integer] The size of HDD
+* `*is_main` - (Optional)[boolean] Indicates if HDD is to be used as main hard disk of the server
+* `image` -(Required)[string] The name of a desired image to be provisioned with the server
+* `ip` - (Optional)[string] IP address for the server
+* `loadbalancer_id` - (Optional)[string] ID of the load balancer
+* `monitoring_policy_id` - (Optional)[string] ID of monitoring policy
+* `name` -(Required)[string] The name of the server.
+* `password` - (Optional)[string] Desired password.
+* `ram` -(Required)[float] Size of ram.
+* `ssh_key_path` - (Optional)[string] Path to private ssh key
+* `vcores` -(Required)[integer] Number of virtual cores.
diff --git a/website/source/docs/providers/oneandone/r/oneandone_shared_storage.html.markdown b/website/source/docs/providers/oneandone/r/oneandone_shared_storage.html.markdown
new file mode 100644
index 000000000..a8fe8224f
--- /dev/null
+++ b/website/source/docs/providers/oneandone/r/oneandone_shared_storage.html.markdown
@@ -0,0 +1,43 @@
+---
+layout: "oneandone"
+page_title: "1&1: oneandone_shared_storage"
+sidebar_current: "docs-oneandone-resource-shared-storage"
+description: |-
+ Creates and manages 1&1 Shared Storage.
+---
+
+# oneandone\_server
+
+Manages a Shared Storage on 1&1
+
+## Example Usage
+
+```
+resource "oneandone_shared_storage" "storage" {
+ name = "test_storage1"
+ description = "1234"
+ size = 50
+
+ storage_servers = [
+ {
+ id = "${oneandone_server.server.id}"
+ rights = "RW"
+ },
+ {
+ id = "${oneandone_server.server02.id}"
+ rights = "RW"
+ }
+ ]
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `datacenter` - (Optional)[string] Location of desired 1and1 datacenter ["DE", "GB", "US", "ES" ]
+* `description` - (Optional)[string] Description for the shared storage
+* `size` - (Required)[string] Size of the shared storage
+* `storage_servers` (Optional)[Collection] List of servers that will have access to the stored storage
+ * `id` - (Required) [string] ID of the server
+ * `rights` - (Required)[string] Access rights to be assigned to the server ["RW","R"]
diff --git a/website/source/docs/providers/oneandone/r/oneandone_vpn.html.markdown b/website/source/docs/providers/oneandone/r/oneandone_vpn.html.markdown
new file mode 100644
index 000000000..4b79e0ca7
--- /dev/null
+++ b/website/source/docs/providers/oneandone/r/oneandone_vpn.html.markdown
@@ -0,0 +1,30 @@
+---
+layout: "oneandone"
+page_title: "1&1: oneandone_vpn"
+sidebar_current: "docs-oneandone-resource-vpn"
+description: |-
+ Creates and manages 1&1 VPN.
+---
+
+# oneandone\_vpn
+
+Manages a VPN on 1&1
+
+## Example Usage
+
+```
+resource "oneandone_public_ip" "ip" {
+ "ip_type" = "IPV4"
+ "reverse_dns" = "test.1and1.com"
+ "datacenter" = "GB"
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `datacenter` - (Optional)[string] Location of desired 1and1 datacenter ["DE", "GB", "US", "ES" ]
+* `ip_type` - (Required)[string] IPV4 or IPV6
+* `reverese_dns` - [Optional](string)
+