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
7865026e
Commit
7865026e
authored
Oct 28, 2014
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1463 from vtolstov/digitalocean
add digitalocean v2 api support
parents
2c052fa8
10612b5d
Changes
13
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
926 additions
and
420 deletions
+926
-420
builder/digitalocean/api.go
builder/digitalocean/api.go
+43
-393
builder/digitalocean/api_v1.go
builder/digitalocean/api_v1.go
+382
-0
builder/digitalocean/api_v2.go
builder/digitalocean/api_v2.go
+448
-0
builder/digitalocean/artifact.go
builder/digitalocean/artifact.go
+1
-1
builder/digitalocean/builder.go
builder/digitalocean/builder.go
+24
-10
builder/digitalocean/step_create_droplet.go
builder/digitalocean/step_create_droplet.go
+2
-2
builder/digitalocean/step_create_ssh_key.go
builder/digitalocean/step_create_ssh_key.go
+3
-4
builder/digitalocean/step_droplet_info.go
builder/digitalocean/step_droplet_info.go
+2
-1
builder/digitalocean/step_power_off.go
builder/digitalocean/step_power_off.go
+3
-2
builder/digitalocean/step_shutdown.go
builder/digitalocean/step_shutdown.go
+4
-3
builder/digitalocean/step_snapshot.go
builder/digitalocean/step_snapshot.go
+3
-2
builder/digitalocean/wait.go
builder/digitalocean/wait.go
+1
-1
website/source/docs/builders/digitalocean.html.markdown
website/source/docs/builders/digitalocean.html.markdown
+10
-1
No files found.
builder/digitalocean/api.go
View file @
7865026e
This diff is collapsed.
Click to expand it.
builder/digitalocean/api_v1.go
0 → 100644
View file @
7865026e
// 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"
"log"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/mitchellh/mapstructure"
)
type
DigitalOceanClientV1
struct
{
// The http client for communicating
client
*
http
.
Client
// Credentials
ClientID
string
APIKey
string
// The base URL of the API
APIURL
string
}
// Creates a new client for communicating with DO
func
DigitalOceanClientNewV1
(
client
string
,
key
string
,
url
string
)
*
DigitalOceanClientV1
{
c
:=
&
DigitalOceanClientV1
{
client
:
&
http
.
Client
{
Transport
:
&
http
.
Transport
{
Proxy
:
http
.
ProxyFromEnvironment
,
},
},
APIURL
:
url
,
ClientID
:
client
,
APIKey
:
key
,
}
return
c
}
// Creates an SSH Key and returns it's id
func
(
d
DigitalOceanClientV1
)
CreateKey
(
name
string
,
pub
string
)
(
uint
,
error
)
{
params
:=
url
.
Values
{}
params
.
Set
(
"name"
,
name
)
params
.
Set
(
"ssh_pub_key"
,
pub
)
body
,
err
:=
NewRequestV1
(
d
,
"ssh_keys/new"
,
params
)
if
err
!=
nil
{
return
0
,
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
DigitalOceanClientV1
)
DestroyKey
(
id
uint
)
error
{
path
:=
fmt
.
Sprintf
(
"ssh_keys/%v/destroy"
,
id
)
_
,
err
:=
NewRequestV1
(
d
,
path
,
url
.
Values
{})
return
err
}
// Creates a droplet and returns it's id
func
(
d
DigitalOceanClientV1
)
CreateDroplet
(
name
string
,
size
string
,
image
string
,
region
string
,
keyId
uint
,
privateNetworking
bool
)
(
uint
,
error
)
{
params
:=
url
.
Values
{}
params
.
Set
(
"name"
,
name
)
found_size
,
err
:=
d
.
Size
(
size
)
if
err
!=
nil
{
return
0
,
fmt
.
Errorf
(
"Invalid size or lookup failure: '%s': %s"
,
size
,
err
)
}
found_image
,
err
:=
d
.
Image
(
image
)
if
err
!=
nil
{
return
0
,
fmt
.
Errorf
(
"Invalid image or lookup failure: '%s': %s"
,
image
,
err
)
}
found_region
,
err
:=
d
.
Region
(
region
)
if
err
!=
nil
{
return
0
,
fmt
.
Errorf
(
"Invalid region or lookup failure: '%s': %s"
,
region
,
err
)
}
params
.
Set
(
"size_slug"
,
found_size
.
Slug
)
params
.
Set
(
"image_slug"
,
found_image
.
Slug
)
params
.
Set
(
"region_slug"
,
found_region
.
Slug
)
params
.
Set
(
"ssh_key_ids"
,
fmt
.
Sprintf
(
"%v"
,
keyId
))
params
.
Set
(
"private_networking"
,
fmt
.
Sprintf
(
"%v"
,
privateNetworking
))
body
,
err
:=
NewRequestV1
(
d
,
"droplets/new"
,
params
)
if
err
!=
nil
{
return
0
,
err
}
// Read the Droplets ID
droplet
:=
body
[
"droplet"
]
.
(
map
[
string
]
interface
{})
dropletId
:=
droplet
[
"id"
]
.
(
float64
)
return
uint
(
dropletId
),
err
}
// Destroys a droplet
func
(
d
DigitalOceanClientV1
)
DestroyDroplet
(
id
uint
)
error
{
path
:=
fmt
.
Sprintf
(
"droplets/%v/destroy"
,
id
)
_
,
err
:=
NewRequestV1
(
d
,
path
,
url
.
Values
{})
return
err
}
// Powers off a droplet
func
(
d
DigitalOceanClientV1
)
PowerOffDroplet
(
id
uint
)
error
{
path
:=
fmt
.
Sprintf
(
"droplets/%v/power_off"
,
id
)
_
,
err
:=
NewRequestV1
(
d
,
path
,
url
.
Values
{})
return
err
}
// Shutsdown a droplet. This is a "soft" shutdown.
func
(
d
DigitalOceanClientV1
)
ShutdownDroplet
(
id
uint
)
error
{
path
:=
fmt
.
Sprintf
(
"droplets/%v/shutdown"
,
id
)
_
,
err
:=
NewRequestV1
(
d
,
path
,
url
.
Values
{})
return
err
}
// Creates a snaphot of a droplet by it's ID
func
(
d
DigitalOceanClientV1
)
CreateSnapshot
(
id
uint
,
name
string
)
error
{
path
:=
fmt
.
Sprintf
(
"droplets/%v/snapshot"
,
id
)
params
:=
url
.
Values
{}
params
.
Set
(
"name"
,
name
)
_
,
err
:=
NewRequestV1
(
d
,
path
,
params
)
return
err
}
// Returns all available images.
func
(
d
DigitalOceanClientV1
)
Images
()
([]
Image
,
error
)
{
resp
,
err
:=
NewRequestV1
(
d
,
"images"
,
url
.
Values
{})
if
err
!=
nil
{
return
nil
,
err
}
var
result
ImagesResp
if
err
:=
mapstructure
.
Decode
(
resp
,
&
result
);
err
!=
nil
{
return
nil
,
err
}
return
result
.
Images
,
nil
}
// Destroys an image by its ID.
func
(
d
DigitalOceanClientV1
)
DestroyImage
(
id
uint
)
error
{
path
:=
fmt
.
Sprintf
(
"images/%d/destroy"
,
id
)
_
,
err
:=
NewRequestV1
(
d
,
path
,
url
.
Values
{})
return
err
}
// Returns DO's string representation of status "off" "new" "active" etc.
func
(
d
DigitalOceanClientV1
)
DropletStatus
(
id
uint
)
(
string
,
string
,
error
)
{
path
:=
fmt
.
Sprintf
(
"droplets/%v"
,
id
)
body
,
err
:=
NewRequestV1
(
d
,
path
,
url
.
Values
{})
if
err
!=
nil
{
return
""
,
""
,
err
}
var
ip
string
// Read the droplet's "status"
droplet
:=
body
[
"droplet"
]
.
(
map
[
string
]
interface
{})
status
:=
droplet
[
"status"
]
.
(
string
)
if
droplet
[
"ip_address"
]
!=
nil
{
ip
=
droplet
[
"ip_address"
]
.
(
string
)
}
return
ip
,
status
,
err
}
// Sends an api request and returns a generic map[string]interface of
// the response.
func
NewRequestV1
(
d
DigitalOceanClientV1
,
path
string
,
params
url
.
Values
)
(
map
[
string
]
interface
{},
error
)
{
client
:=
d
.
client
// Add the authentication parameters
params
.
Set
(
"client_id"
,
d
.
ClientID
)
params
.
Set
(
"api_key"
,
d
.
APIKey
)
url
:=
fmt
.
Sprintf
(
"%s/%s?%s"
,
d
.
APIURL
,
path
,
params
.
Encode
())
// Do some basic scrubbing so sensitive information doesn't appear in logs
scrubbedUrl
:=
strings
.
Replace
(
url
,
d
.
ClientID
,
"CLIENT_ID"
,
-
1
)
scrubbedUrl
=
strings
.
Replace
(
scrubbedUrl
,
d
.
APIKey
,
"API_KEY"
,
-
1
)
log
.
Printf
(
"sending new request to digitalocean: %s"
,
scrubbedUrl
)
var
lastErr
error
for
attempts
:=
1
;
attempts
<
10
;
attempts
++
{
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
}
log
.
Printf
(
"response from digitalocean: %s"
,
body
)
var
decodedResponse
map
[
string
]
interface
{}
err
=
json
.
Unmarshal
(
body
,
&
decodedResponse
)
if
err
!=
nil
{
err
=
errors
.
New
(
fmt
.
Sprintf
(
"Failed to decode JSON response (HTTP %v) from DigitalOcean: %s"
,
resp
.
StatusCode
,
body
))
return
decodedResponse
,
err
}
// Check for errors sent by digitalocean
status
:=
decodedResponse
[
"status"
]
.
(
string
)
if
status
==
"OK"
{
return
decodedResponse
,
nil
}
if
status
==
"ERROR"
{
statusRaw
,
ok
:=
decodedResponse
[
"error_message"
]
if
ok
{
status
=
statusRaw
.
(
string
)
}
else
{
status
=
fmt
.
Sprintf
(
"Unknown error. Full response body: %s"
,
body
)
}
}
lastErr
=
errors
.
New
(
fmt
.
Sprintf
(
"Received error from DigitalOcean (%d): %s"
,
resp
.
StatusCode
,
status
))
log
.
Println
(
lastErr
)
if
strings
.
Contains
(
status
,
"a pending event"
)
{
// Retry, DigitalOcean sends these dumb "pending event"
// errors all the time.
time
.
Sleep
(
5
*
time
.
Second
)
continue
}
// Some other kind of error. Just return.
return
decodedResponse
,
lastErr
}
return
nil
,
lastErr
}
func
(
d
DigitalOceanClientV1
)
Image
(
slug_or_name_or_id
string
)
(
Image
,
error
)
{
images
,
err
:=
d
.
Images
()
if
err
!=
nil
{
return
Image
{},
err
}
for
_
,
image
:=
range
images
{
if
strings
.
EqualFold
(
image
.
Slug
,
slug_or_name_or_id
)
{
return
image
,
nil
}
}
for
_
,
image
:=
range
images
{
if
strings
.
EqualFold
(
image
.
Name
,
slug_or_name_or_id
)
{
return
image
,
nil
}
}
for
_
,
image
:=
range
images
{
id
,
err
:=
strconv
.
Atoi
(
slug_or_name_or_id
)
if
err
==
nil
{
if
image
.
Id
==
uint
(
id
)
{
return
image
,
nil
}
}
}
err
=
errors
.
New
(
fmt
.
Sprintf
(
"Unknown image '%v'"
,
slug_or_name_or_id
))
return
Image
{},
err
}
// Returns all available regions.
func
(
d
DigitalOceanClientV1
)
Regions
()
([]
Region
,
error
)
{
resp
,
err
:=
NewRequestV1
(
d
,
"regions"
,
url
.
Values
{})
if
err
!=
nil
{
return
nil
,
err
}
var
result
RegionsResp
if
err
:=
mapstructure
.
Decode
(
resp
,
&
result
);
err
!=
nil
{
return
nil
,
err
}
return
result
.
Regions
,
nil
}
func
(
d
DigitalOceanClientV1
)
Region
(
slug_or_name_or_id
string
)
(
Region
,
error
)
{
regions
,
err
:=
d
.
Regions
()
if
err
!=
nil
{
return
Region
{},
err
}
for
_
,
region
:=
range
regions
{
if
strings
.
EqualFold
(
region
.
Slug
,
slug_or_name_or_id
)
{
return
region
,
nil
}
}
for
_
,
region
:=
range
regions
{
if
strings
.
EqualFold
(
region
.
Name
,
slug_or_name_or_id
)
{
return
region
,
nil
}
}
for
_
,
region
:=
range
regions
{
id
,
err
:=
strconv
.
Atoi
(
slug_or_name_or_id
)
if
err
==
nil
{
if
region
.
Id
==
uint
(
id
)
{
return
region
,
nil
}
}
}
err
=
errors
.
New
(
fmt
.
Sprintf
(
"Unknown region '%v'"
,
slug_or_name_or_id
))
return
Region
{},
err
}
// Returns all available sizes.
func
(
d
DigitalOceanClientV1
)
Sizes
()
([]
Size
,
error
)
{
resp
,
err
:=
NewRequestV1
(
d
,
"sizes"
,
url
.
Values
{})
if
err
!=
nil
{
return
nil
,
err
}
var
result
SizesResp
if
err
:=
mapstructure
.
Decode
(
resp
,
&
result
);
err
!=
nil
{
return
nil
,
err
}
return
result
.
Sizes
,
nil
}
func
(
d
DigitalOceanClientV1
)
Size
(
slug_or_name_or_id
string
)
(
Size
,
error
)
{
sizes
,
err
:=
d
.
Sizes
()
if
err
!=
nil
{
return
Size
{},
err
}
for
_
,
size
:=
range
sizes
{
if
strings
.
EqualFold
(
size
.
Slug
,
slug_or_name_or_id
)
{
return
size
,
nil
}
}
for
_
,
size
:=
range
sizes
{
if
strings
.
EqualFold
(
size
.
Name
,
slug_or_name_or_id
)
{
return
size
,
nil
}
}
for
_
,
size
:=
range
sizes
{
id
,
err
:=
strconv
.
Atoi
(
slug_or_name_or_id
)
if
err
==
nil
{
if
size
.
Id
==
uint
(
id
)
{
return
size
,
nil
}
}
}
err
=
errors
.
New
(
fmt
.
Sprintf
(
"Unknown size '%v'"
,
slug_or_name_or_id
))
return
Size
{},
err
}
builder/digitalocean/api_v2.go
0 → 100644
View file @
7865026e
This diff is collapsed.
Click to expand it.
builder/digitalocean/artifact.go
View file @
7865026e
...
...
@@ -16,7 +16,7 @@ type Artifact struct {
regionName
string
// The client for making API calls
client
*
DigitalOceanClient
client
DigitalOceanClient
}
func
(
*
Artifact
)
BuilderId
()
string
{
...
...
builder/digitalocean/builder.go
View file @
7865026e
...
...
@@ -40,6 +40,7 @@ type config struct {
ClientID
string
`mapstructure:"client_id"`
APIKey
string
`mapstructure:"api_key"`
APIURL
string
`mapstructure:"api_url"`
APIToken
string
`mapstructure:"api_token"`
RegionID
uint
`mapstructure:"region_id"`
SizeID
uint
`mapstructure:"size_id"`
ImageID
uint
`mapstructure:"image_id"`
...
...
@@ -101,6 +102,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b
.
config
.
APIURL
=
os
.
Getenv
(
"DIGITALOCEAN_API_URL"
)
}
if
b
.
config
.
APIToken
==
""
{
// Default to environment variable for api_token, if it exists
b
.
config
.
APIToken
=
os
.
Getenv
(
"DIGITALOCEAN_API_TOKEN"
)
}
if
b
.
config
.
Region
==
""
{
if
b
.
config
.
RegionID
!=
0
{
b
.
config
.
Region
=
fmt
.
Sprintf
(
"%v"
,
b
.
config
.
RegionID
)
...
...
@@ -164,6 +170,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
"client_id"
:
&
b
.
config
.
ClientID
,
"api_key"
:
&
b
.
config
.
APIKey
,
"api_url"
:
&
b
.
config
.
APIURL
,
"api_token"
:
&
b
.
config
.
APIToken
,
"snapshot_name"
:
&
b
.
config
.
SnapshotName
,
"droplet_name"
:
&
b
.
config
.
DropletName
,
"ssh_username"
:
&
b
.
config
.
SSHUsername
,
...
...
@@ -180,19 +187,21 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}
}
if
b
.
config
.
APIToken
==
""
{
// Required configurations that will display errors if not set
if
b
.
config
.
ClientID
==
""
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
errors
.
New
(
"a client_id must be specified"
))
}
if
b
.
config
.
APIURL
==
""
{
b
.
config
.
APIURL
=
"https://api.digitalocean.com"
errs
,
errors
.
New
(
"a client_id for v1 auth or api_token for v2 auth must be specified"
))
}
if
b
.
config
.
APIKey
==
""
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
errors
.
New
(
"an api_key must be specified"
))
errs
,
errors
.
New
(
"a api_key for v1 auth or api_token for v2 auth must be specified"
))
}
}
if
b
.
config
.
APIURL
==
""
{
b
.
config
.
APIURL
=
"https://api.digitalocean.com"
}
sshTimeout
,
err
:=
time
.
ParseDuration
(
b
.
config
.
RawSSHTimeout
)
...
...
@@ -218,8 +227,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}
func
(
b
*
Builder
)
Run
(
ui
packer
.
Ui
,
hook
packer
.
Hook
,
cache
packer
.
Cache
)
(
packer
.
Artifact
,
error
)
{
var
client
DigitalOceanClient
// Initialize the DO API client
client
:=
DigitalOceanClient
{}
.
New
(
b
.
config
.
ClientID
,
b
.
config
.
APIKey
,
b
.
config
.
APIURL
)
if
b
.
config
.
APIToken
==
""
{
client
=
DigitalOceanClientNewV1
(
b
.
config
.
ClientID
,
b
.
config
.
APIKey
,
b
.
config
.
APIURL
)
}
else
{
client
=
DigitalOceanClientNewV2
(
b
.
config
.
APIToken
,
b
.
config
.
APIURL
)
}
// Set up the state
state
:=
new
(
multistep
.
BasicStateBag
)
...
...
builder/digitalocean/step_create_droplet.go
View file @
7865026e
...
...
@@ -12,7 +12,7 @@ type stepCreateDroplet struct {
}
func
(
s
*
stepCreateDroplet
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
DigitalOceanClient
)
client
:=
state
.
Get
(
"client"
)
.
(
DigitalOceanClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
c
:=
state
.
Get
(
"config"
)
.
(
config
)
sshKeyId
:=
state
.
Get
(
"ssh_key_id"
)
.
(
uint
)
...
...
@@ -44,7 +44,7 @@ func (s *stepCreateDroplet) Cleanup(state multistep.StateBag) {
return
}
client
:=
state
.
Get
(
"client"
)
.
(
*
DigitalOceanClient
)
client
:=
state
.
Get
(
"client"
)
.
(
DigitalOceanClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
c
:=
state
.
Get
(
"config"
)
.
(
config
)
...
...
builder/digitalocean/step_create_ssh_key.go
View file @
7865026e
...
...
@@ -19,7 +19,7 @@ type stepCreateSSHKey struct {
}
func
(
s
*
stepCreateSSHKey
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
DigitalOceanClient
)
client
:=
state
.
Get
(
"client"
)
.
(
DigitalOceanClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
.
Say
(
"Creating temporary ssh key for droplet..."
)
...
...
@@ -71,15 +71,14 @@ func (s *stepCreateSSHKey) Cleanup(state multistep.StateBag) {
return
}
client
:=
state
.
Get
(
"client"
)
.
(
*
DigitalOceanClient
)
client
:=
state
.
Get
(
"client"
)
.
(
DigitalOceanClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
c
:=
state
.
Get
(
"config"
)
.
(
config
)
ui
.
Say
(
"Deleting temporary ssh key..."
)
err
:=
client
.
DestroyKey
(
s
.
keyId
)
curlstr
:=
fmt
.
Sprintf
(
"curl '%v/ssh_keys/%v/destroy?client_id=%v&api_key=%v'"
,
c
.
APIURL
,
s
.
keyId
,
c
.
ClientID
,
c
.
APIKey
)
curlstr
:=
fmt
.
Sprintf
(
"curl -H 'Authorization: Bearer #TOKEN#' -X DELETE '%v/v2/account/keys/%v'"
,
c
.
APIURL
,
s
.
keyId
)
if
err
!=
nil
{
log
.
Printf
(
"Error cleaning up ssh key: %v"
,
err
.
Error
())
...
...
builder/digitalocean/step_droplet_info.go
View file @
7865026e
...
...
@@ -2,6 +2,7 @@ package digitalocean
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
...
...
@@ -9,7 +10,7 @@ import (
type
stepDropletInfo
struct
{}
func
(
s
*
stepDropletInfo
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
DigitalOceanClient
)
client
:=
state
.
Get
(
"client"
)
.
(
DigitalOceanClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
c
:=
state
.
Get
(
"config"
)
.
(
config
)
dropletId
:=
state
.
Get
(
"droplet_id"
)
.
(
uint
)
...
...
builder/digitalocean/step_power_off.go
View file @
7865026e
...
...
@@ -2,15 +2,16 @@ package digitalocean
import
(
"fmt"
"log"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
)
type
stepPowerOff
struct
{}
func
(
s
*
stepPowerOff
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
DigitalOceanClient
)
client
:=
state
.
Get
(
"client"
)
.
(
DigitalOceanClient
)
c
:=
state
.
Get
(
"config"
)
.
(
config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
dropletId
:=
state
.
Get
(
"droplet_id"
)
.
(
uint
)
...
...
builder/digitalocean/step_shutdown.go
View file @
7865026e
...
...
@@ -2,16 +2,17 @@ package digitalocean
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"time"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type
stepShutdown
struct
{}
func
(
s
*
stepShutdown
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
DigitalOceanClient
)
client
:=
state
.
Get
(
"client"
)
.
(
DigitalOceanClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
dropletId
:=
state
.
Get
(
"droplet_id"
)
.
(
uint
)
...
...
builder/digitalocean/step_snapshot.go
View file @
7865026e
...
...
@@ -3,15 +3,16 @@ package digitalocean
import
(
"errors"
"fmt"
"log"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
)
type
stepSnapshot
struct
{}
func
(
s
*
stepSnapshot
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
DigitalOceanClient
)
client
:=
state
.
Get
(
"client"
)
.
(
DigitalOceanClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
c
:=
state
.
Get
(
"config"
)
.
(
config
)
dropletId
:=
state
.
Get
(
"droplet_id"
)
.
(
uint
)
...
...
builder/digitalocean/wait.go
View file @
7865026e
...
...
@@ -8,7 +8,7 @@ import (
// waitForState simply blocks until the droplet is in
// a state we expect, while eventually timing out.
func
waitForDropletState
(
desiredState
string
,
dropletId
uint
,
client
*
DigitalOceanClient
,
timeout
time
.
Duration
)
error
{
func
waitForDropletState
(
desiredState
string
,
dropletId
uint
,
client
DigitalOceanClient
,
timeout
time
.
Duration
)
error
{
done
:=
make
(
chan
struct
{})
defer
close
(
done
)
...
...
website/source/docs/builders/digitalocean.html.markdown
View file @
7865026e
...
...
@@ -24,7 +24,7 @@ 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.
### Required:
### Required
v1 api
:
*
`api_key`
(string) - The API key to use to access your account. You can
retrieve this on the "API" page visible after logging into your account
...
...
@@ -38,8 +38,17 @@ each category, the available configuration keys are alphabetized.
If not specified, Packer will use the environment variable
`DIGITALOCEAN_CLIENT_ID`
, if set.
### Required v2 api:
*
`api_token`
(string) - The client TOKEN to use to access your account. If it
specified, then use v2 api (current), if not then used old (v1) deprecated api.
Also it can be specified via environment variable
`DIGITALOCEAN_API_TOKEN`
, if set.
### Optional:
*
`api_url`
(string) - API endpoint, by default use https://api.digitalocean.com
Also it can be specified via environment variable
`DIGITALOCEAN_API_URL`
, if set.
*
`droplet_name`
(string) - The name assigned to the droplet. DigitalOcean
sets the hostname of the machine to this value.
...
...
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