Packer Builder 1&1

This commit is contained in:
jasminSPC 2016-11-13 23:34:36 +01:00
parent 671f15572d
commit 4bcba37f38
37 changed files with 7328 additions and 0 deletions

View File

@ -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
}

View File

@ -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()
}
}

View File

@ -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"
}]
}
`

View File

@ -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")
}
}

View File

@ -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
}

29
builder/oneandone/ssh.go Normal file
View File

@ -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
}

View File

@ -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())
}
}

View File

@ -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) {}

View File

@ -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) {
}

View File

@ -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),

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

6
vendor/vendor.json vendored
View File

@ -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",

View File

@ -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"
}
]
}
```