From 4bcba37f38894c32283b051db0fc47c303e8bdc6 Mon Sep 17 00:00:00 2001 From: jasminSPC Date: Sun, 13 Nov 2016 23:34:36 +0100 Subject: [PATCH 1/6] Packer Builder 1&1 --- builder/oneandone/artifact.go | 34 + builder/oneandone/builder.go | 84 + builder/oneandone/builder_acc_test.go | 33 + builder/oneandone/builder_test.go | 55 + builder/oneandone/config.go | 87 + builder/oneandone/ssh.go | 29 + builder/oneandone/step_create_server.go | 117 + builder/oneandone/step_create_sshkey.go | 105 + builder/oneandone/step_take_snapshot.go | 49 + command/plugin.go | 2 + .../oneandone-cloudserver-sdk-go/LICENSE | 202 ++ .../oneandone-cloudserver-sdk-go/README.md | 2573 +++++++++++++++++ .../datacenters.go | 36 + .../oneandone-cloudserver-sdk-go/dvdisos.go | 48 + .../oneandone-cloudserver-sdk-go/errors.go | 27 + .../firewallpolicies.go | 208 ++ .../oneandone-cloudserver-sdk-go/images.go | 110 + .../loadbalancers.go | 219 ++ .../oneandone-cloudserver-sdk-go/logs.go | 50 + .../monitoringcenter.go | 158 + .../monitoringpolicies.go | 305 ++ .../oneandone-cloudserver-sdk-go/oneandone.go | 163 ++ .../oneandone-cloudserver-sdk-go/ping.go | 29 + .../oneandone-cloudserver-sdk-go/pricing.go | 40 + .../privatenetworks.go | 149 + .../oneandone-cloudserver-sdk-go/publicips.go | 108 + .../restclient.go | 213 ++ .../oneandone-cloudserver-sdk-go/roles.go | 595 ++++ .../serverappliances.go | 48 + .../oneandone-cloudserver-sdk-go/servers.go | 808 ++++++ .../oneandone-cloudserver-sdk-go/setup.go | 19 + .../sharedstorages.go | 190 ++ .../oneandone-cloudserver-sdk-go/usages.go | 52 + .../oneandone-cloudserver-sdk-go/users.go | 205 ++ .../oneandone-cloudserver-sdk-go/vpns.go | 114 + vendor/vendor.json | 6 + .../source/docs/builders/oneandone.html.md | 58 + 37 files changed, 7328 insertions(+) create mode 100644 builder/oneandone/artifact.go create mode 100644 builder/oneandone/builder.go create mode 100644 builder/oneandone/builder_acc_test.go create mode 100644 builder/oneandone/builder_test.go create mode 100644 builder/oneandone/config.go create mode 100644 builder/oneandone/ssh.go create mode 100644 builder/oneandone/step_create_server.go create mode 100644 builder/oneandone/step_create_sshkey.go create mode 100644 builder/oneandone/step_take_snapshot.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/LICENSE create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/README.md create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/datacenters.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/dvdisos.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/errors.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/firewallpolicies.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/images.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/loadbalancers.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/logs.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/monitoringcenter.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/monitoringpolicies.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/oneandone.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/ping.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/pricing.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/privatenetworks.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/publicips.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/restclient.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/roles.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/serverappliances.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/servers.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/setup.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/sharedstorages.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/usages.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/users.go create mode 100644 vendor/github.com/1and1/oneandone-cloudserver-sdk-go/vpns.go create mode 100644 website/source/docs/builders/oneandone.html.md diff --git a/builder/oneandone/artifact.go b/builder/oneandone/artifact.go new file mode 100644 index 000000000..52c3d456f --- /dev/null +++ b/builder/oneandone/artifact.go @@ -0,0 +1,34 @@ +package oneandone + +import ( + "fmt" +) + +type Artifact struct { + snapshotId string + snapshotName string +} + +func (*Artifact) BuilderId() string { + return BuilderId +} + +func (a *Artifact) Files() []string { + return []string{} +} + +func (*Artifact) Id() string { + return "Null" +} + +func (a *Artifact) String() string { + return fmt.Sprintf("A snapshot was created: '%v', '%v'", a.snapshotId, a.snapshotName) +} + +func (a *Artifact) State(name string) interface{} { + return nil +} + +func (a *Artifact) Destroy() error { + return nil +} diff --git a/builder/oneandone/builder.go b/builder/oneandone/builder.go new file mode 100644 index 000000000..6820558c4 --- /dev/null +++ b/builder/oneandone/builder.go @@ -0,0 +1,84 @@ +package oneandone + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/communicator" + "github.com/mitchellh/packer/packer" + "log" +) + +const BuilderId = "packer.oneandone" + +type Builder struct { + config *Config + runner multistep.Runner +} + +func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { + c, warnings, errs := NewConfig(raws...) + if errs != nil { + return warnings, errs + } + b.config = c + + return warnings, nil +} + +func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { + + steps := []multistep.Step{ + &StepCreateSSHKey{ + Debug: b.config.PackerDebug, + DebugKeyPath: fmt.Sprintf("oneandone_%s", b.config.SnapshotName), + }, + new(stepCreateServer), + &communicator.StepConnect{ + Config: &b.config.Comm, + Host: commHost, + SSHConfig: sshConfig, + }, + &common.StepProvision{}, + new(stepTakeSnapshot), + } + + state := new(multistep.BasicStateBag) + + state.Put("config", b.config) + state.Put("hook", hook) + state.Put("ui", ui) + config := state.Get("config").(*Config) + + if b.config.PackerDebug { + b.runner = &multistep.DebugRunner{ + Steps: steps, + PauseFn: common.MultistepDebugFn(ui), + } + } else { + b.runner = &multistep.BasicRunner{Steps: steps} + } + + b.runner.Run(state) + + if rawErr, ok := state.GetOk("error"); ok { + return nil, rawErr.(error) + } + + config.SnapshotName = state.Get("snapshot_name").(string) + snapshotId := state.Get("snapshot_id").(string) + + artifact := &Artifact{ + snapshotName: config.SnapshotName, + snapshotId: snapshotId, + } + + return artifact, nil +} + +func (b *Builder) Cancel() { + if b.runner != nil { + log.Println("Cancelling the step runner...") + b.runner.Cancel() + } +} diff --git a/builder/oneandone/builder_acc_test.go b/builder/oneandone/builder_acc_test.go new file mode 100644 index 000000000..a15dce6d5 --- /dev/null +++ b/builder/oneandone/builder_acc_test.go @@ -0,0 +1,33 @@ +package oneandone + +import ( + "os" + "testing" + + builderT "github.com/mitchellh/packer/helper/builder/testing" +) + +func TestBuilderAcc_basic(t *testing.T) { + builderT.Test(t, builderT.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Builder: &Builder{}, + Template: testBuilderAccBasic, + }) +} + +func testAccPreCheck(t *testing.T) { + if v := os.Getenv("ONEANDONE_TOKEN"); v == "" { + t.Fatal("ONEANDONE_TOKEN must be set for acceptance tests") + } +} + +const testBuilderAccBasic = ` +{ + "builders": [{ + "type": "oneandone", + "disk_size": "50", + "snapshot_name": "test5", + "image" : "ubuntu1604-64min" + }] +} +` diff --git a/builder/oneandone/builder_test.go b/builder/oneandone/builder_test.go new file mode 100644 index 000000000..808caf46a --- /dev/null +++ b/builder/oneandone/builder_test.go @@ -0,0 +1,55 @@ +package oneandone + +import ( + "fmt" + "github.com/mitchellh/packer/packer" + "testing" +) + +func testConfig() map[string]interface{} { + return map[string]interface{}{ + "type": "oneandone", + "disk_size": "50", + "snapshot_name": "test5", + "image": "ubuntu1604-64min", + } +} + +func TestImplementsBuilder(t *testing.T) { + var raw interface{} + raw = &Builder{} + if _, ok := raw.(packer.Builder); !ok { + t.Fatalf("Builder should be a builder") + } +} + +func TestBuilder_Prepare_BadType(t *testing.T) { + b := &Builder{} + c := map[string]interface{}{ + "api_key": []string{}, + } + + warns, err := b.Prepare(c) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err == nil { + fmt.Println(err) + fmt.Println(warns) + t.Fatalf("prepare should fail") + } +} + +func TestBuilderPrepare_InvalidKey(t *testing.T) { + var b Builder + config := testConfig() + + config["i_should_not_be_valid"] = true + warnings, err := b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err == nil { + t.Fatal("should have error") + } +} diff --git a/builder/oneandone/config.go b/builder/oneandone/config.go new file mode 100644 index 000000000..5a8c97441 --- /dev/null +++ b/builder/oneandone/config.go @@ -0,0 +1,87 @@ +package oneandone + +import ( + "github.com/1and1/oneandone-cloudserver-sdk-go" + "github.com/mitchellh/mapstructure" + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/communicator" + "github.com/mitchellh/packer/helper/config" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" + "os" +) + +type Config struct { + common.PackerConfig `mapstructure:",squash"` + Comm communicator.Config `mapstructure:",squash"` + + Token string `mapstructure:"token"` + Url string `mapstructure:"url"` + SSHKey string + SSHKey_path string `mapstructure:"ssh_key_path"` + SnapshotName string `mapstructure:"image_name"` + Image string `mapstructure:"source_image_name"` + ImagePassword string `mapstructure:"image_password"` + DiskSize int `mapstructure:"disk_size"` + Timeout int `mapstructure:"timeout"` + CommConfig communicator.Config `mapstructure:",squash"` + ctx interpolate.Context +} + +func NewConfig(raws ...interface{}) (*Config, []string, error) { + var c Config + + var md mapstructure.Metadata + err := config.Decode(&c, &config.DecodeOpts{ + Metadata: &md, + Interpolate: true, + InterpolateContext: &c.ctx, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{ + "run_command", + }, + }, + }, raws...) + if err != nil { + return nil, nil, err + } + + var errs *packer.MultiError + + if c.Comm.SSHUsername == "" { + c.Comm.SSHUsername = "root" + } + c.Comm.SSHPort = 22 + + if c.Token == "" { + c.Token = os.Getenv("ONEANDONE_TOKEN") + } + + if c.Url == "" { + c.Url = oneandone.BaseUrl + } + + if c.DiskSize == 0 { + c.DiskSize = 50 + } + + if c.Image == "" { + c.Image = "ubuntu1604-64std" + } + + if c.Timeout == 0 { + c.Timeout = 600 + } + + if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { + errs = packer.MultiErrorAppend(errs, es...) + } + c.Comm.SSHPort = 22 + + if errs != nil && len(errs.Errors) > 0 { + return nil, nil, errs + } + common.ScrubConfig(c, c.Token) + + return &c, nil, nil +} diff --git a/builder/oneandone/ssh.go b/builder/oneandone/ssh.go new file mode 100644 index 000000000..49a0b08b0 --- /dev/null +++ b/builder/oneandone/ssh.go @@ -0,0 +1,29 @@ +package oneandone + +import ( + "fmt" + "github.com/mitchellh/multistep" + "golang.org/x/crypto/ssh" +) + +func commHost(state multistep.StateBag) (string, error) { + ipAddress := state.Get("server_ip").(string) + return ipAddress, nil +} + +func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) { + config := state.Get("config").(*Config) + privateKey := state.Get("privateKey").(string) + + signer, err := ssh.ParsePrivateKey([]byte(privateKey)) + if err != nil { + return nil, fmt.Errorf("Error setting up SSH config: %s", err) + } + + return &ssh.ClientConfig{ + User: config.Comm.SSHUsername, + Auth: []ssh.AuthMethod{ + ssh.PublicKeys(signer), + }, + }, nil +} diff --git a/builder/oneandone/step_create_server.go b/builder/oneandone/step_create_server.go new file mode 100644 index 000000000..9580a8bd6 --- /dev/null +++ b/builder/oneandone/step_create_server.go @@ -0,0 +1,117 @@ +package oneandone + +import ( + "fmt" + "github.com/1and1/oneandone-cloudserver-sdk-go" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "strings" + "time" +) + +type stepCreateServer struct{} + +func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + c := state.Get("config").(*Config) + + c.SSHKey = state.Get("publicKey").(string) + + token := oneandone.SetToken(c.Token) + //Create an API client + api := oneandone.New(token, c.Url) + + // List server appliances + saps, _ := api.ListServerAppliances() + + time.Sleep(time.Second * 10) + + var sa oneandone.ServerAppliance + for _, a := range saps { + + if a.Type == "IMAGE" && strings.Contains(strings.ToLower(a.Name), strings.ToLower(c.Image)) { + sa = a + break + } + } + + c.SSHKey = state.Get("publicKey").(string) + if c.DiskSize < sa.MinHddSize { + ui.Error(fmt.Sprintf("Minimum required disk size %d", sa.MinHddSize)) + } + + ui.Say("Creating Server...") + + // Create a server + req := oneandone.ServerRequest{ + Name: c.SnapshotName, + Description: "Example server description.", + ApplianceId: sa.Id, + PowerOn: true, + SSHKey: c.SSHKey, + Hardware: oneandone.Hardware{ + Vcores: 1, + CoresPerProcessor: 1, + Ram: 2, + Hdds: []oneandone.Hdd{ + { + Size: c.DiskSize, + IsMain: true, + }, + }, + }, + } + + if c.ImagePassword != "" { + req.Password = c.ImagePassword + } + 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", 1, c.Timeout) + } else { + ui.Error(err.Error()) + return multistep.ActionHalt + } + + // Get a server + server, err = api.GetServer(server_id) + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt + } + + state.Put("server_id", server_id) + + state.Put("server_ip", server.Ips[0].Ip) + + return multistep.ActionContinue +} + +func (s *stepCreateServer) Cleanup(state multistep.StateBag) { + c := state.Get("config").(*Config) + ui := state.Get("ui").(packer.Ui) + + ui.Say("Removing Server...") + + token := oneandone.SetToken(c.Token) + //Create an API client + api := oneandone.New(token, oneandone.BaseUrl) + + serverId := state.Get("server_id").(string) + + server, err := api.ShutdownServer(serverId, false) + if err != nil { + ui.Error(fmt.Sprintf("Error shutting down 1and1 server. Please destroy it manually: %s", serverId)) + ui.Error(err.Error()) + } + err = api.WaitForState(server, "POWERED_OFF", 1, c.Timeout) + + server, err = api.DeleteServer(server.Id, false) + + if err != nil { + ui.Error(fmt.Sprintf("Error deleting 1and1 server. Please destroy it manually: %s", serverId)) + ui.Error(err.Error()) + } +} diff --git a/builder/oneandone/step_create_sshkey.go b/builder/oneandone/step_create_sshkey.go new file mode 100644 index 000000000..9ccdf054c --- /dev/null +++ b/builder/oneandone/step_create_sshkey.go @@ -0,0 +1,105 @@ +package oneandone + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + "os" + + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "golang.org/x/crypto/ssh" + "io/ioutil" +) + +type StepCreateSSHKey struct { + Debug bool + DebugKeyPath string +} + +func (s *StepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + c := state.Get("config").(*Config) + + if c.SSHKey_path == "" { + ui.Say("Creating temporary SSH key for instance...") + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + err := fmt.Errorf("Error creating temporary ssh key: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + priv_blk := pem.Block{ + Type: "RSA PRIVATE KEY", + Headers: nil, + Bytes: x509.MarshalPKCS1PrivateKey(priv), + } + + pub, err := ssh.NewPublicKey(&priv.PublicKey) + if err != nil { + err := fmt.Errorf("Error creating temporary ssh key: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk))) + state.Put("publicKey", string(ssh.MarshalAuthorizedKey(pub))) + + ui.Message(fmt.Sprintf("Saving key to: %s", s.DebugKeyPath)) + f, err := os.Create(s.DebugKeyPath) + if err != nil { + state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) + return multistep.ActionHalt + } + + f.Chmod(os.FileMode(int(0700))) + err = pem.Encode(f, &priv_blk) + f.Close() + if err != nil { + state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) + return multistep.ActionHalt + } + } else { + ui.Say(c.SSHKey_path) + pemBytes, err := ioutil.ReadFile(c.SSHKey_path) + + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt + } + + block, _ := pem.Decode(pemBytes) + + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + + if err != nil { + err := fmt.Errorf("Error creating temporary ssh key: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + priv_blk := pem.Block{ + Type: "RSA PRIVATE KEY", + Headers: nil, + Bytes: x509.MarshalPKCS1PrivateKey(priv), + } + + pub, err := ssh.NewPublicKey(&priv.PublicKey) + if err != nil { + err := fmt.Errorf("Error creating temporary ssh key: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk))) + state.Put("publicKey", string(ssh.MarshalAuthorizedKey(pub))) + } + return multistep.ActionContinue +} + +func (s *StepCreateSSHKey) Cleanup(state multistep.StateBag) {} diff --git a/builder/oneandone/step_take_snapshot.go b/builder/oneandone/step_take_snapshot.go new file mode 100644 index 000000000..8828c123d --- /dev/null +++ b/builder/oneandone/step_take_snapshot.go @@ -0,0 +1,49 @@ +package oneandone + +import ( + "github.com/1and1/oneandone-cloudserver-sdk-go" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" +) + +type stepTakeSnapshot struct{} + +func (s *stepTakeSnapshot) Run(state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + c := state.Get("config").(*Config) + + ui.Say("Creating Snapshot...") + + token := oneandone.SetToken(c.Token) + api := oneandone.New(token, c.Url) + + serverId := state.Get("server_id").(string) + + req := oneandone.ImageConfig{ + Name: c.SnapshotName, + Description: "Packer image", + ServerId: serverId, + Frequency: "WEEKLY", + NumImages: 1, + } + + img_id, img, err := api.CreateImage(&req) + + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt + } else { + api.WaitForState(img, "ENABLED", 1, c.Timeout) + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt + } + } + + state.Put("snapshot_id", img_id) + state.Put("snapshot_name", img.Name) + return multistep.ActionContinue +} + +func (s *stepTakeSnapshot) Cleanup(state multistep.StateBag) { +} diff --git a/command/plugin.go b/command/plugin.go index b20fa0674..dce7d9311 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -24,6 +24,7 @@ import ( filebuilder "github.com/mitchellh/packer/builder/file" googlecomputebuilder "github.com/mitchellh/packer/builder/googlecompute" nullbuilder "github.com/mitchellh/packer/builder/null" + oneandonebuilder "github.com/mitchellh/packer/builder/oneandone" openstackbuilder "github.com/mitchellh/packer/builder/openstack" parallelsisobuilder "github.com/mitchellh/packer/builder/parallels/iso" parallelspvmbuilder "github.com/mitchellh/packer/builder/parallels/pvm" @@ -79,6 +80,7 @@ var Builders = map[string]packer.Builder{ "file": new(filebuilder.Builder), "googlecompute": new(googlecomputebuilder.Builder), "null": new(nullbuilder.Builder), + "oneandone": new(oneandonebuilder.Builder), "openstack": new(openstackbuilder.Builder), "parallels-iso": new(parallelsisobuilder.Builder), "parallels-pvm": new(parallelspvmbuilder.Builder), 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 ad34e1c7a..981743752 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -2,6 +2,12 @@ "comment": "", "ignore": "test appengine", "package": [ + { + "checksumSHA1": "aABATU51PlDHfGeSe5cc9udwSXg=", + "path": "github.com/1and1/oneandone-cloudserver-sdk-go", + "revision": "5678f03fc801525df794f953aa82f5ad7555a2ef", + "revisionTime": "2016-08-11T22:04:02Z" + }, { "checksumSHA1": "/WG++Jij8INZ80tER+FAiIDMmws=", "comment": "v3.1.0-beta", diff --git a/website/source/docs/builders/oneandone.html.md b/website/source/docs/builders/oneandone.html.md new file mode 100644 index 000000000..47b845e46 --- /dev/null +++ b/website/source/docs/builders/oneandone.html.md @@ -0,0 +1,58 @@ +--- +description: | + The 1&1 builder is able to create images for 1&1 cloud. +layout: docs +page_title: 1&1 Builder +... + +# 1&1 Builder + +Type: `oneandone` + +The 1&1 Builder is able to create virtual machines for [One](https://www.1and1.com/). + +## Configuration Reference + +There are many configuration options available for the builder. They are +segmented below into two categories: required and optional parameters. Within +each category, the available configuration keys are alphabetized. + +In addition to the options listed here, a +[communicator](/docs/templates/communicator.html) can be configured for this +builder. + +### Required + +- `source_image_name` (string) - 1&1 Server Appliance name of type `IMAGE`. Defaults to `ubuntu1604-64std` + +- `token` (string) - 1&1 REST API Token. This can be specified via environment variable `ONEANDONE_TOKEN` + +### Optional + +- `disk_size` (string) - Amount of disk space for this image in GB. Defaults to "50" + +- `image_password` (string) - Password for the server images. + +- `image_name` (string) - Resulting image. If "image_name" is not provided Packer will generate it + +- `timeout` (string) - An approximate limit on how long Packer will continue making status requests while waiting for the build to complete. Default value "600". + +- `url` (string) - Endpoint for the 1&1 REST API. Default URL "https://cloudpanel-api.1and1.com/v1" + + +## Example + +Here is a basic example: + +```json +{ + "builders":[ + { + "type":"oneandone", + "disk_size":"50", + "image_name":"test5", + "source_image_name":"ubuntu1604-64min" + } + ] +} +``` \ No newline at end of file From dc231f96004b418840d05f4f1b4c668a33b8c2c9 Mon Sep 17 00:00:00 2001 From: jasminSPC Date: Sun, 13 Nov 2016 23:54:55 +0100 Subject: [PATCH 2/6] PR remarks --- builder/oneandone/config.go | 1 - website/source/docs/builders/oneandone.html.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/builder/oneandone/config.go b/builder/oneandone/config.go index 5a8c97441..88328ea16 100644 --- a/builder/oneandone/config.go +++ b/builder/oneandone/config.go @@ -76,7 +76,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { errs = packer.MultiErrorAppend(errs, es...) } - c.Comm.SSHPort = 22 if errs != nil && len(errs.Errors) > 0 { return nil, nil, errs diff --git a/website/source/docs/builders/oneandone.html.md b/website/source/docs/builders/oneandone.html.md index 47b845e46..e0fddf8f8 100644 --- a/website/source/docs/builders/oneandone.html.md +++ b/website/source/docs/builders/oneandone.html.md @@ -35,7 +35,7 @@ builder. - `image_name` (string) - Resulting image. If "image_name" is not provided Packer will generate it -- `timeout` (string) - An approximate limit on how long Packer will continue making status requests while waiting for the build to complete. Default value "600". +- `timeout` (int) - An approximate limit on how long Packer will continue making status requests while waiting for the build to complete. Default value "600". - `url` (string) - Endpoint for the 1&1 REST API. Default URL "https://cloudpanel-api.1and1.com/v1" From 484960c9d131b42124261453002c295311029734 Mon Sep 17 00:00:00 2001 From: jasminSPC Date: Wed, 16 Nov 2016 00:17:30 +0100 Subject: [PATCH 3/6] Fixes #4169 --- builder/oneandone/artifact.go | 3 + builder/oneandone/builder.go | 28 ++++---- builder/oneandone/config.go | 64 ++++++++++++++----- builder/oneandone/ssh.go | 38 ++++++++--- builder/oneandone/step_create_server.go | 48 +++++++++----- builder/oneandone/step_create_sshkey.go | 53 ++------------- builder/oneandone/step_take_snapshot.go | 15 +++-- builder/profitbricks/builder.go | 9 ++- builder/profitbricks/config.go | 39 +++++------ builder/profitbricks/ssh.go | 38 ++++++++--- builder/profitbricks/step_create_server.go | 45 +++++++++---- builder/profitbricks/step_create_ssh_key.go | 53 ++------------- builder/profitbricks/step_take_snapshot.go | 4 +- vendor/golang.org/x/crypto/ssh/kex.go | 30 ++++++--- vendor/golang.org/x/crypto/ssh/keys.go | 4 +- vendor/vendor.json | 6 +- .../source/docs/builders/oneandone.html.md | 6 +- .../source/docs/builders/profitbricks.html.md | 6 +- 18 files changed, 264 insertions(+), 225 deletions(-) diff --git a/builder/oneandone/artifact.go b/builder/oneandone/artifact.go index 52c3d456f..ffa922475 100644 --- a/builder/oneandone/artifact.go +++ b/builder/oneandone/artifact.go @@ -22,6 +22,9 @@ func (*Artifact) Id() string { } func (a *Artifact) String() string { + if a.snapshotId == "" { + return "No image has been created." + } return fmt.Sprintf("A snapshot was created: '%v', '%v'", a.snapshotId, a.snapshotName) } diff --git a/builder/oneandone/builder.go b/builder/oneandone/builder.go index 6820558c4..050a5f38e 100644 --- a/builder/oneandone/builder.go +++ b/builder/oneandone/builder.go @@ -1,6 +1,7 @@ package oneandone import ( + "errors" "fmt" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/common" @@ -28,6 +29,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { + state := new(multistep.BasicStateBag) + + state.Put("config", b.config) + state.Put("hook", hook) + state.Put("ui", ui) + steps := []multistep.Step{ &StepCreateSSHKey{ Debug: b.config.PackerDebug, @@ -43,13 +50,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe new(stepTakeSnapshot), } - state := new(multistep.BasicStateBag) - - state.Put("config", b.config) - state.Put("hook", hook) - state.Put("ui", ui) - config := state.Get("config").(*Config) - if b.config.PackerDebug { b.runner = &multistep.DebugRunner{ Steps: steps, @@ -65,12 +65,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe return nil, rawErr.(error) } - config.SnapshotName = state.Get("snapshot_name").(string) - snapshotId := state.Get("snapshot_id").(string) + if temp, ok := state.GetOk("snapshot_name"); ok { + b.config.SnapshotName = temp.(string) + } artifact := &Artifact{ - snapshotName: config.SnapshotName, - snapshotId: snapshotId, + snapshotName: b.config.SnapshotName, + } + + if id, ok := state.GetOk("snapshot_id"); ok { + artifact.snapshotId = id.(string) + } else { + return nil, errors.New("Image creation has failed.") } return artifact, nil diff --git a/builder/oneandone/config.go b/builder/oneandone/config.go index 88328ea16..6187cd14f 100644 --- a/builder/oneandone/config.go +++ b/builder/oneandone/config.go @@ -1,6 +1,7 @@ package oneandone import ( + "errors" "github.com/1and1/oneandone-cloudserver-sdk-go" "github.com/mitchellh/mapstructure" "github.com/mitchellh/packer/common" @@ -9,23 +10,24 @@ import ( "github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate" "os" + "strings" ) type Config struct { common.PackerConfig `mapstructure:",squash"` Comm communicator.Config `mapstructure:",squash"` - Token string `mapstructure:"token"` - Url string `mapstructure:"url"` - SSHKey string - SSHKey_path string `mapstructure:"ssh_key_path"` - SnapshotName string `mapstructure:"image_name"` - Image string `mapstructure:"source_image_name"` - ImagePassword string `mapstructure:"image_password"` - DiskSize int `mapstructure:"disk_size"` - Timeout int `mapstructure:"timeout"` - CommConfig communicator.Config `mapstructure:",squash"` - ctx interpolate.Context + Token string `mapstructure:"token"` + Url string `mapstructure:"url"` + SSHKey string + SnapshotName string `mapstructure:"image_name"` + DataCenterName string `mapstructure:"data_center_name"` + DataCenterId string + Image string `mapstructure:"source_image_name"` + DiskSize int `mapstructure:"disk_size"` + Retries int `mapstructure:"retries"` + CommConfig communicator.Config `mapstructure:",squash"` + ctx interpolate.Context } func NewConfig(raws ...interface{}) (*Config, []string, error) { @@ -48,10 +50,24 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { var errs *packer.MultiError + if c.SnapshotName == "" { + def, err := interpolate.Render("packer-{{timestamp}}", nil) + if err != nil { + panic(err) + } + + // Default to packer-{{ unix timestamp (utc) }} + c.SnapshotName = def + } + + if c.Image == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("1&1 'image' is required")) + } + if c.Comm.SSHUsername == "" { c.Comm.SSHUsername = "root" } - c.Comm.SSHPort = 22 if c.Token == "" { c.Token = os.Getenv("ONEANDONE_TOKEN") @@ -65,12 +81,28 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.DiskSize = 50 } - if c.Image == "" { - c.Image = "ubuntu1604-64std" + if c.Retries == 0 { + c.Retries = 600 } - if c.Timeout == 0 { - c.Timeout = 600 + if c.DataCenterName != "" { + token := oneandone.SetToken(c.Token) + + //Create an API client + api := oneandone.New(token, c.Url) + + dcs, err := api.ListDatacenters() + + if err != nil { + errs = packer.MultiErrorAppend( + errs, err) + } + for _, dc := range dcs { + if strings.ToLower(dc.CountryCode) == strings.ToLower(c.DataCenterName) { + c.DataCenterId = dc.Id + break + } + } } if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { diff --git a/builder/oneandone/ssh.go b/builder/oneandone/ssh.go index 49a0b08b0..669c571a5 100644 --- a/builder/oneandone/ssh.go +++ b/builder/oneandone/ssh.go @@ -3,7 +3,8 @@ package oneandone import ( "fmt" "github.com/mitchellh/multistep" - "golang.org/x/crypto/ssh" + "github.com/mitchellh/packer/communicator/ssh" + gossh "golang.org/x/crypto/ssh" ) func commHost(state multistep.StateBag) (string, error) { @@ -11,19 +12,36 @@ func commHost(state multistep.StateBag) (string, error) { return ipAddress, nil } -func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) { +func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { config := state.Get("config").(*Config) - privateKey := state.Get("privateKey").(string) + var privateKey string - signer, err := ssh.ParsePrivateKey([]byte(privateKey)) - if err != nil { - return nil, fmt.Errorf("Error setting up SSH config: %s", err) + var auth []gossh.AuthMethod + + if config.Comm.SSHPassword != "" { + auth = []gossh.AuthMethod{ + gossh.Password(config.Comm.SSHPassword), + gossh.KeyboardInteractive( + ssh.PasswordKeyboardInteractive(config.Comm.SSHPassword)), + } } - return &ssh.ClientConfig{ + if config.Comm.SSHPrivateKey != "" { + if priv, ok := state.GetOk("privateKey"); ok { + privateKey = priv.(string) + } + signer, err := gossh.ParsePrivateKey([]byte(privateKey)) + if err != nil { + return nil, fmt.Errorf("Error setting up SSH config: %s", err) + } + if err != nil { + return nil, err + } + + auth = append(auth, gossh.PublicKeys(signer)) + } + return &gossh.ClientConfig{ User: config.Comm.SSHUsername, - Auth: []ssh.AuthMethod{ - ssh.PublicKeys(signer), - }, + Auth: auth, }, nil } diff --git a/builder/oneandone/step_create_server.go b/builder/oneandone/step_create_server.go index 9580a8bd6..f6825a00b 100644 --- a/builder/oneandone/step_create_server.go +++ b/builder/oneandone/step_create_server.go @@ -15,9 +15,12 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) c := state.Get("config").(*Config) - c.SSHKey = state.Get("publicKey").(string) + if sshkey, ok := state.GetOk("publicKey"); ok { + c.SSHKey = sshkey.(string) + } token := oneandone.SetToken(c.Token) + //Create an API client api := oneandone.New(token, c.Url) @@ -35,7 +38,6 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { } } - c.SSHKey = state.Get("publicKey").(string) if c.DiskSize < sa.MinHddSize { ui.Error(fmt.Sprintf("Minimum required disk size %d", sa.MinHddSize)) } @@ -48,7 +50,6 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { Description: "Example server description.", ApplianceId: sa.Id, PowerOn: true, - SSHKey: c.SSHKey, Hardware: oneandone.Hardware{ Vcores: 1, CoresPerProcessor: 1, @@ -62,14 +63,22 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { }, } - if c.ImagePassword != "" { - req.Password = c.ImagePassword + if c.DataCenterId != "" { + req.DatacenterId = c.DataCenterId } + + if c.Comm.SSHPassword != "" { + req.Password = c.Comm.SSHPassword + } + if c.SSHKey != "" { + req.SSHKey = c.SSHKey + } + 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", 1, c.Timeout) + err = api.WaitForState(server, "POWERED_ON", 10, c.Retries) } else { ui.Error(err.Error()) return multistep.ActionHalt @@ -99,19 +108,24 @@ func (s *stepCreateServer) Cleanup(state multistep.StateBag) { //Create an API client api := oneandone.New(token, oneandone.BaseUrl) - serverId := state.Get("server_id").(string) - - server, err := api.ShutdownServer(serverId, false) - if err != nil { - ui.Error(fmt.Sprintf("Error shutting down 1and1 server. Please destroy it manually: %s", serverId)) - ui.Error(err.Error()) + var serverId string + if temp, ok := state.GetOk("server_id"); ok { + serverId = temp.(string) } - err = api.WaitForState(server, "POWERED_OFF", 1, c.Timeout) - server, err = api.DeleteServer(server.Id, false) + if serverId != "" { + server, err := api.ShutdownServer(serverId, false) + if err != nil { + ui.Error(fmt.Sprintf("Error shutting down 1and1 server. Please destroy it manually: %s", serverId)) + ui.Error(err.Error()) + } + err = api.WaitForState(server, "POWERED_OFF", 10, c.Retries) - if err != nil { - ui.Error(fmt.Sprintf("Error deleting 1and1 server. Please destroy it manually: %s", serverId)) - ui.Error(err.Error()) + server, err = api.DeleteServer(server.Id, false) + + if err != nil { + ui.Error(fmt.Sprintf("Error deleting 1and1 server. Please destroy it manually: %s", serverId)) + ui.Error(err.Error()) + } } } diff --git a/builder/oneandone/step_create_sshkey.go b/builder/oneandone/step_create_sshkey.go index 9ccdf054c..bb655d39d 100644 --- a/builder/oneandone/step_create_sshkey.go +++ b/builder/oneandone/step_create_sshkey.go @@ -1,13 +1,9 @@ package oneandone import ( - "crypto/rand" - "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" - "os" - "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" "golang.org/x/crypto/ssh" @@ -23,49 +19,8 @@ func (s *StepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) c := state.Get("config").(*Config) - if c.SSHKey_path == "" { - ui.Say("Creating temporary SSH key for instance...") - priv, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - err := fmt.Errorf("Error creating temporary ssh key: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - priv_blk := pem.Block{ - Type: "RSA PRIVATE KEY", - Headers: nil, - Bytes: x509.MarshalPKCS1PrivateKey(priv), - } - - pub, err := ssh.NewPublicKey(&priv.PublicKey) - if err != nil { - err := fmt.Errorf("Error creating temporary ssh key: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk))) - state.Put("publicKey", string(ssh.MarshalAuthorizedKey(pub))) - - ui.Message(fmt.Sprintf("Saving key to: %s", s.DebugKeyPath)) - f, err := os.Create(s.DebugKeyPath) - if err != nil { - state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) - return multistep.ActionHalt - } - - f.Chmod(os.FileMode(int(0700))) - err = pem.Encode(f, &priv_blk) - f.Close() - if err != nil { - state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) - return multistep.ActionHalt - } - } else { - ui.Say(c.SSHKey_path) - pemBytes, err := ioutil.ReadFile(c.SSHKey_path) + if c.Comm.SSHPrivateKey != "" { + pemBytes, err := ioutil.ReadFile(c.Comm.SSHPrivateKey) if err != nil { ui.Error(err.Error()) @@ -77,8 +32,8 @@ func (s *StepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { - err := fmt.Errorf("Error creating temporary ssh key: %s", err) - state.Put("error", err) + + state.Put("error", err.Error()) ui.Error(err.Error()) return multistep.ActionHalt } diff --git a/builder/oneandone/step_take_snapshot.go b/builder/oneandone/step_take_snapshot.go index 8828c123d..8483ff830 100644 --- a/builder/oneandone/step_take_snapshot.go +++ b/builder/oneandone/step_take_snapshot.go @@ -18,6 +18,8 @@ func (s *stepTakeSnapshot) Run(state multistep.StateBag) multistep.StepAction { api := oneandone.New(token, c.Url) serverId := state.Get("server_id").(string) + ui.Say("Snapshot Name " + c.SnapshotName) + ui.Say("server id " + serverId) req := oneandone.ImageConfig{ Name: c.SnapshotName, @@ -32,12 +34,13 @@ func (s *stepTakeSnapshot) Run(state multistep.StateBag) multistep.StepAction { if err != nil { ui.Error(err.Error()) return multistep.ActionHalt - } else { - api.WaitForState(img, "ENABLED", 1, c.Timeout) - if err != nil { - ui.Error(err.Error()) - return multistep.ActionHalt - } + } + + err = api.WaitForState(img, "ENABLED", 10, c.Retries) + + if err != nil { + ui.Error(err.Error()) + return multistep.ActionHalt } state.Put("snapshot_id", img_id) diff --git a/builder/profitbricks/builder.go b/builder/profitbricks/builder.go index af95608d7..a7f3a371f 100644 --- a/builder/profitbricks/builder.go +++ b/builder/profitbricks/builder.go @@ -27,7 +27,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { + state := new(multistep.BasicStateBag) + state.Put("config", b.config) + state.Put("hook", hook) + state.Put("ui", ui) steps := []multistep.Step{ &StepCreateSSHKey{ Debug: b.config.PackerDebug, @@ -43,11 +47,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe new(stepTakeSnapshot), } - state := new(multistep.BasicStateBag) - - state.Put("config", b.config) - state.Put("hook", hook) - state.Put("ui", ui) config := state.Get("config").(*Config) if b.config.PackerDebug { diff --git a/builder/profitbricks/config.go b/builder/profitbricks/config.go index 27e3aa24a..bc51decde 100644 --- a/builder/profitbricks/config.go +++ b/builder/profitbricks/config.go @@ -19,19 +19,17 @@ type Config struct { PBPassword string `mapstructure:"password"` PBUrl string `mapstructure:"url"` - Region string `mapstructure:"location"` - Image string `mapstructure:"image"` - SSHKey string - SSHKey_path string `mapstructure:"ssh_key_path"` - SnapshotName string `mapstructure:"snapshot_name"` - SnapshotPassword string `mapstructure:"snapshot_password"` - DiskSize int `mapstructure:"disk_size"` - DiskType string `mapstructure:"disk_type"` - Cores int `mapstructure:"cores"` - Ram int `mapstructure:"ram"` - Timeout int `mapstructure:"timeout"` - CommConfig communicator.Config `mapstructure:",squash"` - ctx interpolate.Context + Region string `mapstructure:"location"` + Image string `mapstructure:"image"` + SSHKey string + SnapshotName string `mapstructure:"snapshot_name"` + DiskSize int `mapstructure:"disk_size"` + DiskType string `mapstructure:"disk_type"` + Cores int `mapstructure:"cores"` + Ram int `mapstructure:"ram"` + Retries int `mapstructure:"retries"` + CommConfig communicator.Config `mapstructure:",squash"` + ctx interpolate.Context } func NewConfig(raws ...interface{}) (*Config, []string, error) { @@ -54,10 +52,13 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { var errs *packer.MultiError + if c.Comm.SSHPassword == "" && c.Comm.SSHPrivateKey == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("Either ssh private key path or ssh password must be set.")) + } if c.Comm.SSHUsername == "" { c.Comm.SSHUsername = "root" } - c.Comm.SSHPort = 22 if c.SnapshotName == "" { def, err := interpolate.Render("packer-{{timestamp}}", nil) @@ -81,10 +82,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { c.PBUrl = "https://api.profitbricks.com/rest/v2" } - if c.Image == "" { - c.Image = "Ubuntu-16.04" - } - if c.Cores == 0 { c.Cores = 4 } @@ -108,7 +105,11 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { if es := c.Comm.Prepare(&c.ctx); len(es) > 0 { errs = packer.MultiErrorAppend(errs, es...) } - c.Comm.SSHPort = 22 + + if c.Image == "" { + errs = packer.MultiErrorAppend( + errs, errors.New("ProfitBricks 'image' is required")) + } if c.PBUsername == "" { errs = packer.MultiErrorAppend( diff --git a/builder/profitbricks/ssh.go b/builder/profitbricks/ssh.go index 93a5c1c0a..55aa80950 100644 --- a/builder/profitbricks/ssh.go +++ b/builder/profitbricks/ssh.go @@ -3,7 +3,8 @@ package profitbricks import ( "fmt" "github.com/mitchellh/multistep" - "golang.org/x/crypto/ssh" + "github.com/mitchellh/packer/communicator/ssh" + gossh "golang.org/x/crypto/ssh" ) func commHost(state multistep.StateBag) (string, error) { @@ -11,19 +12,36 @@ func commHost(state multistep.StateBag) (string, error) { return ipAddress, nil } -func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) { +func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { config := state.Get("config").(*Config) - privateKey := state.Get("privateKey").(string) + var privateKey string - signer, err := ssh.ParsePrivateKey([]byte(privateKey)) - if err != nil { - return nil, fmt.Errorf("Error setting up SSH config: %s", err) + var auth []gossh.AuthMethod + + if config.Comm.SSHPassword != "" { + auth = []gossh.AuthMethod{ + gossh.Password(config.Comm.SSHPassword), + gossh.KeyboardInteractive( + ssh.PasswordKeyboardInteractive(config.Comm.SSHPassword)), + } } - return &ssh.ClientConfig{ + if config.Comm.SSHPrivateKey != "" { + if priv, ok := state.GetOk("privateKey"); ok { + privateKey = priv.(string) + } + signer, err := gossh.ParsePrivateKey([]byte(privateKey)) + if err != nil { + return nil, fmt.Errorf("Error setting up SSH config: %s", err) + } + if err != nil { + return nil, err + } + + auth = append(auth, gossh.PublicKeys(signer)) + } + return &gossh.ClientConfig{ User: config.Comm.SSHUsername, - Auth: []ssh.AuthMethod{ - ssh.PublicKeys(signer), - }, + Auth: auth, }, nil } diff --git a/builder/profitbricks/step_create_server.go b/builder/profitbricks/step_create_server.go index fa57ad1b2..90c7bd2e2 100644 --- a/builder/profitbricks/step_create_server.go +++ b/builder/profitbricks/step_create_server.go @@ -20,8 +20,9 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { profitbricks.SetAuth(c.PBUsername, c.PBPassword) profitbricks.SetDepth("5") - c.SSHKey = state.Get("publicKey").(string) - + if sshkey, ok := state.GetOk("publicKey"); ok { + c.SSHKey = sshkey.(string) + } ui.Say("Creating Virtual Data Center...") img := s.getImageId(c.Image, c) @@ -44,12 +45,10 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { Items: []profitbricks.Volume{ { Properties: profitbricks.VolumeProperties{ - Type: c.DiskType, - Size: c.DiskSize, - Name: c.SnapshotName, - Image: img, - SshKeys: []string{c.SSHKey}, - ImagePassword: c.SnapshotPassword, + Type: c.DiskType, + Size: c.DiskSize, + Name: c.SnapshotName, + Image: img, }, }, }, @@ -60,6 +59,13 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { }, }, } + if c.SSHKey != "" { + datacenter.Entities.Servers.Items[0].Entities.Volumes.Items[0].Properties.SshKeys = []string{c.SSHKey} + } + + if c.Comm.SSHPassword != "" { + datacenter.Entities.Servers.Items[0].Entities.Volumes.Items[0].Properties.ImagePassword = c.Comm.SSHPassword + } datacenter = profitbricks.CompositeCreateDatacenter(datacenter) if datacenter.StatusCode > 299 { @@ -74,7 +80,12 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } } - s.waitTillProvisioned(datacenter.Headers.Get("Location"), *c) + + err := s.waitTillProvisioned(datacenter.Headers.Get("Location"), *c) + if err != nil { + ui.Error(fmt.Sprintf("Error occured while creating a datacenter %s", err.Error())) + return multistep.ActionHalt + } state.Put("datacenter_id", datacenter.Id) @@ -90,7 +101,11 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } - s.waitTillProvisioned(lan.Headers.Get("Location"), *c) + err = s.waitTillProvisioned(lan.Headers.Get("Location"), *c) + if err != nil { + ui.Error(fmt.Sprintf("Error occured while creating a LAN %s", err.Error())) + return multistep.ActionHalt + } lanId, _ := strconv.Atoi(lan.Id) nic := profitbricks.CreateNic(datacenter.Id, datacenter.Entities.Servers.Items[0].Id, profitbricks.Nic{ @@ -106,7 +121,11 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } - s.waitTillProvisioned(nic.Headers.Get("Location"), *c) + err = s.waitTillProvisioned(nic.Headers.Get("Location"), *c) + if err != nil { + ui.Error(fmt.Sprintf("Error occured while creating a NIC %s", err.Error())) + return multistep.ActionHalt + } state.Put("volume_id", datacenter.Entities.Servers.Items[0].Entities.Volumes.Items[0].Id) @@ -139,8 +158,8 @@ func (s *stepCreateServer) Cleanup(state multistep.StateBag) { func (d *stepCreateServer) waitTillProvisioned(path string, config Config) error { d.setPB(config.PBUsername, config.PBPassword, config.PBUrl) waitCount := 120 - if config.Timeout > 0 { - waitCount = config.Timeout + if config.Retries > 0 { + waitCount = config.Retries } for i := 0; i < waitCount; i++ { request := profitbricks.GetRequestStatus(path) diff --git a/builder/profitbricks/step_create_ssh_key.go b/builder/profitbricks/step_create_ssh_key.go index d2b6b04c1..eba23fc9d 100644 --- a/builder/profitbricks/step_create_ssh_key.go +++ b/builder/profitbricks/step_create_ssh_key.go @@ -1,13 +1,9 @@ package profitbricks import ( - "crypto/rand" - "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" - "os" - "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" "golang.org/x/crypto/ssh" @@ -23,49 +19,8 @@ func (s *StepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) c := state.Get("config").(*Config) - if c.SSHKey_path == "" { - ui.Say("Creating temporary SSH key for instance...") - priv, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - err := fmt.Errorf("Error creating temporary ssh key: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - priv_blk := pem.Block{ - Type: "RSA PRIVATE KEY", - Headers: nil, - Bytes: x509.MarshalPKCS1PrivateKey(priv), - } - - pub, err := ssh.NewPublicKey(&priv.PublicKey) - if err != nil { - err := fmt.Errorf("Error creating temporary ssh key: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk))) - state.Put("publicKey", string(ssh.MarshalAuthorizedKey(pub))) - - ui.Message(fmt.Sprintf("Saving key to: %s", s.DebugKeyPath)) - f, err := os.Create(s.DebugKeyPath) - if err != nil { - state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) - return multistep.ActionHalt - } - - f.Chmod(os.FileMode(int(0700))) - err = pem.Encode(f, &priv_blk) - f.Close() - if err != nil { - state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) - return multistep.ActionHalt - } - } else { - ui.Say(c.SSHKey_path) - pemBytes, err := ioutil.ReadFile(c.SSHKey_path) + if c.Comm.SSHPrivateKey != "" { + pemBytes, err := ioutil.ReadFile(c.Comm.SSHPrivateKey) if err != nil { ui.Error(err.Error()) @@ -77,8 +32,8 @@ func (s *StepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction { priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { - err := fmt.Errorf("Error creating temporary ssh key: %s", err) - state.Put("error", err) + + state.Put("error", err.Error()) ui.Error(err.Error()) return multistep.ActionHalt } diff --git a/builder/profitbricks/step_take_snapshot.go b/builder/profitbricks/step_take_snapshot.go index e4133df92..65bbe7373 100644 --- a/builder/profitbricks/step_take_snapshot.go +++ b/builder/profitbricks/step_take_snapshot.go @@ -57,8 +57,8 @@ func (d *stepTakeSnapshot) checkForErrors(instance profitbricks.Resp) error { func (d *stepTakeSnapshot) waitTillProvisioned(path string, config Config) { d.setPB(config.PBUsername, config.PBPassword, config.PBUrl) waitCount := 50 - if config.Timeout > 0 { - waitCount = config.Timeout + if config.Retries > 0 { + waitCount = config.Retries } for i := 0; i < waitCount; i++ { request := profitbricks.GetRequestStatus(path) diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go index 9285ee31d..c87fbebfd 100644 --- a/vendor/golang.org/x/crypto/ssh/kex.go +++ b/vendor/golang.org/x/crypto/ssh/kex.go @@ -77,11 +77,11 @@ type kexAlgorithm interface { // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. type dhGroup struct { - g, p *big.Int + g, p, pMinus1 *big.Int } func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { - if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 { + if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { return nil, errors.New("ssh: DH parameter out of bounds") } return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil @@ -90,10 +90,17 @@ func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { hashFunc := crypto.SHA1 - x, err := rand.Int(randSource, group.p) - if err != nil { - return nil, err + var x *big.Int + for { + var err error + if x, err = rand.Int(randSource, group.pMinus1); err != nil { + return nil, err + } + if x.Sign() > 0 { + break + } } + X := new(big.Int).Exp(group.g, x, group.p) kexDHInit := kexDHInitMsg{ X: X, @@ -146,9 +153,14 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha return } - y, err := rand.Int(randSource, group.p) - if err != nil { - return + var y *big.Int + for { + if y, err = rand.Int(randSource, group.pMinus1); err != nil { + return + } + if y.Sign() > 0 { + break + } } Y := new(big.Int).Exp(group.g, y, group.p) @@ -373,6 +385,7 @@ func init() { kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ g: new(big.Int).SetInt64(2), p: p, + pMinus1: new(big.Int).Sub(p, bigOne), } // This is the group called diffie-hellman-group14-sha1 in RFC @@ -382,6 +395,7 @@ func init() { kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ g: new(big.Int).SetInt64(2), p: p, + pMinus1: new(big.Int).Sub(p, bigOne), } kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go index e13cf9ce1..f2fc9b6c9 100644 --- a/vendor/golang.org/x/crypto/ssh/keys.go +++ b/vendor/golang.org/x/crypto/ssh/keys.go @@ -722,8 +722,8 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { } // NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, -// ed25519.PublicKey, or any other crypto.Signer and returns a corresponding -// Signer instance. ECDSA keys must use P-256, P-384 or P-521. +// or ed25519.PublicKey returns a corresponding PublicKey instance. +// ECDSA keys must use P-256, P-384 or P-521. func NewPublicKey(key interface{}) (PublicKey, error) { switch key := key.(type) { case *rsa.PublicKey: diff --git a/vendor/vendor.json b/vendor/vendor.json index 981743752..5bae88015 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -739,10 +739,10 @@ "revision": "1f22c0103821b9390939b6776727195525381532" }, { - "checksumSHA1": "1LydpuiE3oBdkbYvSdKKwe9lsLs=", + "checksumSHA1": "LlElMHeTC34ng8eHzjvtUhAgrr8=", "path": "golang.org/x/crypto/ssh", - "revision": "7682e7e3945130cf3cde089834664f68afdd1523", - "revisionTime": "2016-10-03T20:54:26Z" + "revision": "9477e0b78b9ac3d0b03822fd95422e2fe07627cd", + "revisionTime": "2016-10-31T15:37:30Z" }, { "checksumSHA1": "SJ3Ma3Ozavxpbh1usZWBCnzMKIc=", diff --git a/website/source/docs/builders/oneandone.html.md b/website/source/docs/builders/oneandone.html.md index e0fddf8f8..a74212c47 100644 --- a/website/source/docs/builders/oneandone.html.md +++ b/website/source/docs/builders/oneandone.html.md @@ -23,19 +23,21 @@ builder. ### Required -- `source_image_name` (string) - 1&1 Server Appliance name of type `IMAGE`. Defaults to `ubuntu1604-64std` +- `source_image_name` (string) - 1&1 Server Appliance name of type `IMAGE`. - `token` (string) - 1&1 REST API Token. This can be specified via environment variable `ONEANDONE_TOKEN` ### Optional +- `data_center_name` - Name of virtual data center. Possible values "ES", "US", "GB", "DE". Default value "US" + - `disk_size` (string) - Amount of disk space for this image in GB. Defaults to "50" - `image_password` (string) - Password for the server images. - `image_name` (string) - Resulting image. If "image_name" is not provided Packer will generate it -- `timeout` (int) - An approximate limit on how long Packer will continue making status requests while waiting for the build to complete. Default value "600". +- `retries` (int) - Number of retries Packer will make status requests while waiting for the build to complete. Default value "600". - `url` (string) - Endpoint for the 1&1 REST API. Default URL "https://cloudpanel-api.1and1.com/v1" diff --git a/website/source/docs/builders/profitbricks.html.md b/website/source/docs/builders/profitbricks.html.md index 5df07ad34..30a494348 100644 --- a/website/source/docs/builders/profitbricks.html.md +++ b/website/source/docs/builders/profitbricks.html.md @@ -23,7 +23,7 @@ builder. ### Required -- `image` (string) - ProfitBricks volume image. Only Linux public images are supported. Defaults to "Ubuntu-16.04". To obtain full list of available images you can use [ProfitBricks CLI](https://github.com/profitbricks/profitbricks-cli#image). +- `image` (string) - ProfitBricks volume image. Only Linux public images are supported. To obtain full list of available images you can use [ProfitBricks CLI](https://github.com/profitbricks/profitbricks-cli#image). - `password` (string) - ProfitBricks password. This can be specified via environment variable `PROFITBRICKS_PASSWORD', if provided. The value definded in the config has precedence over environemnt variable. @@ -42,12 +42,12 @@ builder. - `ram` (integer) - Amount of RAM to use for this image. Defalts to "2048". +- `retries` (string) - Number of retries Packer will make status requests while waiting for the build to complete. Default value 120 seconds. + - `snapshot_name` (string) - If snapshot name is not provided Packer will generate it - `snapshot_password` (string) - Password for the snapshot. -- `timeout` (string) - An approximate limit on how long Packer will continue making status requests while waiting for the build to complete. Default value 120 seconds. - - `url` (string) - Endpoint for the ProfitBricks REST API. Default URL "https://api.profitbricks.com/rest/v2" From 5649940faba5c074541a53006f3f262631a86a9e Mon Sep 17 00:00:00 2001 From: jasminSPC Date: Wed, 16 Nov 2016 00:20:22 +0100 Subject: [PATCH 4/6] Removed unecessary print messages --- builder/oneandone/step_take_snapshot.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/builder/oneandone/step_take_snapshot.go b/builder/oneandone/step_take_snapshot.go index 8483ff830..8e8cb88fd 100644 --- a/builder/oneandone/step_take_snapshot.go +++ b/builder/oneandone/step_take_snapshot.go @@ -18,8 +18,6 @@ func (s *stepTakeSnapshot) Run(state multistep.StateBag) multistep.StepAction { api := oneandone.New(token, c.Url) serverId := state.Get("server_id").(string) - ui.Say("Snapshot Name " + c.SnapshotName) - ui.Say("server id " + serverId) req := oneandone.ImageConfig{ Name: c.SnapshotName, From 68ca7490bbb465964ce2d4e5070d4dcecbbe42d4 Mon Sep 17 00:00:00 2001 From: jasminSPC Date: Thu, 17 Nov 2016 21:15:28 +0100 Subject: [PATCH 5/6] Removed default value for ssh_username --- builder/oneandone/config.go | 4 ---- builder/profitbricks/config.go | 3 --- website/source/docs/builders/oneandone.html.md | 3 ++- website/source/docs/builders/profitbricks.html.md | 1 + 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/builder/oneandone/config.go b/builder/oneandone/config.go index 6187cd14f..fcc3fca97 100644 --- a/builder/oneandone/config.go +++ b/builder/oneandone/config.go @@ -65,10 +65,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs, errors.New("1&1 'image' is required")) } - if c.Comm.SSHUsername == "" { - c.Comm.SSHUsername = "root" - } - if c.Token == "" { c.Token = os.Getenv("ONEANDONE_TOKEN") } diff --git a/builder/profitbricks/config.go b/builder/profitbricks/config.go index bc51decde..79c697a19 100644 --- a/builder/profitbricks/config.go +++ b/builder/profitbricks/config.go @@ -56,9 +56,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs = packer.MultiErrorAppend( errs, errors.New("Either ssh private key path or ssh password must be set.")) } - if c.Comm.SSHUsername == "" { - c.Comm.SSHUsername = "root" - } if c.SnapshotName == "" { def, err := interpolate.Render("packer-{{timestamp}}", nil) diff --git a/website/source/docs/builders/oneandone.html.md b/website/source/docs/builders/oneandone.html.md index a74212c47..8b81849f9 100644 --- a/website/source/docs/builders/oneandone.html.md +++ b/website/source/docs/builders/oneandone.html.md @@ -53,7 +53,8 @@ Here is a basic example: "type":"oneandone", "disk_size":"50", "image_name":"test5", - "source_image_name":"ubuntu1604-64min" + "source_image_name":"ubuntu1604-64min", + "ssh_username" :"root" } ] } diff --git a/website/source/docs/builders/profitbricks.html.md b/website/source/docs/builders/profitbricks.html.md index 30a494348..e84890544 100644 --- a/website/source/docs/builders/profitbricks.html.md +++ b/website/source/docs/builders/profitbricks.html.md @@ -65,6 +65,7 @@ Here is a basic example: "snapshot_name": "double", "ssh_key_path": "/path/to/private/key", "snapshot_password": "test1234", + "ssh_username" :"root", "timeout": 100 } ] From a239407093e3c342222eb63b8e886563455cb535 Mon Sep 17 00:00:00 2001 From: jasminSPC Date: Mon, 21 Nov 2016 23:02:53 +0100 Subject: [PATCH 6/6] Typo fix --- website/source/docs/builders/oneandone.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/source/docs/builders/oneandone.html.md b/website/source/docs/builders/oneandone.html.md index 8b81849f9..f2c344dec 100644 --- a/website/source/docs/builders/oneandone.html.md +++ b/website/source/docs/builders/oneandone.html.md @@ -9,7 +9,7 @@ page_title: 1&1 Builder Type: `oneandone` -The 1&1 Builder is able to create virtual machines for [One](https://www.1and1.com/). +The 1&1 Builder is able to create virtual machines for [1&1](https://www.1and1.com/). ## Configuration Reference