Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
packer
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kristopher Ruzic
packer
Commits
787a3178
Commit
787a3178
authored
Jun 13, 2013
by
Jack Pearkes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
builder/digitalocean: WIP commit of api interface and initial config
parent
760995db
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
274 additions
and
0 deletions
+274
-0
builder/digitalocean/api.go
builder/digitalocean/api.go
+162
-0
builder/digitalocean/builder.go
builder/digitalocean/builder.go
+112
-0
No files found.
builder/digitalocean/api.go
0 → 100644
View file @
787a3178
// All of the methods used to communicate with the digital_ocean API
// are here. Their API is on a path to V2, so just plain JSON is used
// in place of a proper client library for now.
package
digitalocean
import
(
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
)
const
DIGITALOCEAN_API_URL
=
"https://api.digitalocean.com"
type
DigitalOceanClient
struct
{
// The http client for communicating
client
*
http
.
client
// The base URL of the API
BaseURL
string
// Credentials
ClientID
string
APIKey
string
}
// Creates a new client for communicating with DO
func
(
d
DigitalOceanClient
)
New
(
client
string
,
key
string
)
*
Client
{
c
:=
&
DigitalOceanClient
{
client
:
http
.
DefaultClient
,
BaseURL
:
DIGITALOCEAN_API_URL
,
ClientID
:
client
,
APIKey
:
key
,
}
return
c
}
// Creates an SSH Key and returns it's id
func
(
d
DigitalOceanClient
)
CreateKey
(
name
string
,
pub
string
)
(
uint
,
error
)
{
params
:=
fmt
.
Sprintf
(
"?name=%s&ssh_pub_key=%s"
,
name
,
pub
)
body
,
err
:=
NewRequest
(
d
,
"ssh_keys/new"
,
params
)
if
err
!=
nil
{
return
nil
,
err
}
// Read the SSH key's ID we just created
key
:=
body
[
"ssh_key"
]
.
(
map
[
string
]
interface
{})
keyId
:=
key
[
"id"
]
.
(
float64
)
return
uint
(
keyId
),
nil
}
// Destroys an SSH key
func
(
d
DigitalOceanClient
)
DestroyKey
(
id
uint
)
error
{
path
:=
fmt
.
Sprintf
(
"ssh_keys/%s/destroy"
,
id
)
_
,
err
:=
NewRequest
(
d
,
path
,
""
)
return
err
}
// Creates a droplet and returns it's id
func
(
d
DigitalOceanClient
)
CreateDroplet
(
name
string
,
size
uint
,
image
uint
,
region
uint
,
keyId
uint
)
(
uint
,
error
)
{
params
:=
fmt
.
Sprintf
(
"name=%s&size_id=%s&image_id=%s&size_id=%s&image_id=%s®ion_id=%s&ssh_key_ids=%s"
,
name
,
size
,
image
,
size
,
region
,
keyId
)
body
,
err
:=
NewRequest
(
d
,
"droplets/new"
,
params
)
if
err
!=
nil
{
return
nil
,
err
}
// Read the Droplets ID
droplet
:=
body
[
"droplet"
]
.
(
map
[
string
]
interface
{})
dropletId
:=
droplet
[
"id"
]
.
(
float64
)
return
dropletId
,
err
}
// Destroys a droplet
func
(
d
DigitalOceanClient
)
DestroyDroplet
(
id
uint
)
error
{
path
:=
fmt
.
Sprintf
(
"droplets/%s/destroy"
,
id
)
_
,
err
:=
NewRequest
(
d
,
path
,
""
)
return
err
}
// Powers off a droplet
func
(
d
DigitalOceanClient
)
PowerOffDroplet
(
name
string
,
pub
string
)
error
{
path
:=
fmt
.
Sprintf
(
"droplets/%s/power_off"
,
id
)
_
,
err
:=
NewRequest
(
d
,
path
,
""
)
return
err
}
// Creates a snaphot of a droplet by it's ID
func
(
d
DigitalOceanClient
)
CreateSnapshot
(
id
uint
,
name
string
)
error
{
path
:=
fmt
.
Sprintf
(
"droplets/%s/snapshot"
,
id
)
params
:=
fmt
.
Sprintf
(
"name=%s"
,
name
)
_
,
err
:=
NewRequest
(
d
,
path
,
params
)
return
err
}
// Returns DO's string representation of status "off" "new" "active" etc.
func
(
d
DigitalOceanClient
)
DropletStatus
(
id
uint
)
(
string
,
error
)
{
path
:=
fmt
.
Sprintf
(
"droplets/%s"
,
id
)
body
,
err
:=
NewRequest
(
d
,
path
,
""
)
if
err
!=
nil
{
return
nil
,
err
}
// Read the droplet's "status"
droplet
:=
body
[
"droplet"
]
.
(
map
[
string
]
interface
{})
status
:=
droplet
[
"status"
]
.
(
string
)
return
status
,
err
}
// Sends an api request and returns a generic map[string]interface of
// the response.
func
NewRequest
(
d
DigitalOceanClient
,
path
string
,
params
string
)
(
map
[
string
]
interface
{},
error
)
{
client
:=
d
.
client
url
:=
fmt
.
Sprintf
(
"%s/%s?%s&client_id=%s&api_key=%s"
,
DIGITALOCEAN_API_URL
,
path
,
params
,
d
.
ClientID
,
d
.
APIKey
)
resp
,
err
:=
client
.
Get
(
url
)
if
err
!=
nil
{
return
nil
,
err
}
body
,
err
=
ioutil
.
ReadAll
(
resp
.
Body
)
resp
.
Body
.
Close
()
if
err
!=
nil
{
return
nil
,
err
}
// Catch all non-200 status and return an error
if
resp
.
StatusCode
!=
200
{
err
=
errors
.
New
(
"recieved non-200 status from digitalocean: %d"
,
resp
.
StatusCode
)
return
nil
,
err
}
var
decodedResponse
map
[
string
]
interface
{}
err
=
json
.
Unmarshal
(
body
,
&
decodedResponse
)
if
err
!=
nil
{
return
nil
,
err
}
// Catch all non-OK statuses from DO and return an error
status
:=
decodedResponse
[
"status"
]
if
status
!=
"OK"
{
err
=
errors
.
New
(
"recieved non-OK status from digitalocean: %d"
,
status
)
return
nil
,
err
}
return
decodedResponse
,
nil
}
builder/digitalocean/builder.go
0 → 100644
View file @
787a3178
// The digitalocean package contains a packer.Builder implementation
// that builds DigitalOcean images (snapshots).
package
digitalocean
import
(
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"time"
)
// The unique id for the builder
const
BuilderId
=
"pearkes.digitalocean"
// Configuration tells the builder the credentials
// to use while communicating with DO and describes the image
// you are creating
type
config
struct
{
// Credentials
ClientID
string
`mapstructure:"client_id"`
APIKey
string
`mapstructure:"api_key"`
RegionID
uint
`mapstructure:"region_id"`
SizeID
uint
`mapstructure:"size_id"`
ImageID
uint
`mapstructure:"image_id"`
SSHUsername
string
`mapstructure:"ssh_username"`
SSHPort
uint
`mapstructure:"ssh_port"`
// Configuration for the image being built
SnapshotName
string
`mapstructure:"snapshot_name"`
RawSSHTimeout
string
`mapstructure:"ssh_timeout"`
}
type
Builder
struct
{
config
config
runner
multistep
.
Runner
}
func
(
b
*
Builder
)
Prepare
(
raw
interface
{})
error
{
if
err
:=
mapstructure
.
Decode
(
raw
,
&
b
.
config
);
err
!=
nil
{
return
err
}
// Optional configuration with defaults
//
if
b
.
config
.
RegionID
==
0
{
// Default to Region "New York"
b
.
config
.
RegionID
=
1
}
if
b
.
config
.
SizeID
==
0
{
// Default to 512mb, the smallest droplet size
b
.
config
.
SizeID
=
66
}
if
b
.
config
.
ImageID
==
0
{
// Default to base image "Ubuntu 12.04 x64 Server"
b
.
config
.
ImageID
=
2676
}
if
b
.
config
.
SSHUsername
==
""
{
// Default to "root". You can override this if your
// SourceImage has a different user account then the DO default
b
.
config
.
SSHUsername
=
"root"
}
if
b
.
config
.
SSHPort
==
0
{
// Default to port 22 per DO default
b
.
config
.
SSHPort
=
22
}
if
b
.
config
.
SnapshotName
==
""
{
// Default to packer-{{ unix timestamp (utc) }}
b
.
config
.
SnapshotName
=
"packer-{{.CreateTime}}"
}
if
b
.
config
.
RawSSHTimeout
==
""
{
// Default to 1 minute timeouts
b
.
config
.
RawSSHTimeout
=
"1m"
}
// A list of errors on the configuration
errs
:=
make
([]
error
,
0
)
// Required configurations that will display errors if not set
//
if
b
.
config
.
ClientId
==
""
{
errs
=
append
(
errs
,
errors
.
New
(
"a client_id must be specified"
))
}
if
b
.
config
.
APIKey
==
""
{
errs
=
append
(
errs
,
errors
.
New
(
"an api_key must be specified"
))
}
b
.
config
.
SSHTimeout
,
err
=
time
.
ParseDuration
(
b
.
config
.
RawSSHTimeout
)
if
err
!=
nil
{
errs
=
append
(
errs
,
fmt
.
Errorf
(
"Failed parsing ssh_timeout: %s"
,
err
))
}
if
len
(
errs
)
>
0
{
return
&
packer
.
MultiError
{
errs
}
}
log
.
Printf
(
"Config: %+v"
,
b
.
config
)
return
nil
}
func
(
b
*
Builder
)
Run
(
ui
packer
.
Ui
,
hook
packer
.
Hook
,
cache
packer
.
Cache
)
(
packer
.
Artifact
,
error
)
{
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment