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
dd6e4e49
Commit
dd6e4e49
authored
Jun 13, 2013
by
Jack Pearkes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
builder/digitalocean: connect_ssh, create_droplet, droplet_info
parent
4e699390
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
269 additions
and
4 deletions
+269
-4
builder/digitalocean/api.go
builder/digitalocean/api.go
+4
-3
builder/digitalocean/builder.go
builder/digitalocean/builder.go
+1
-0
builder/digitalocean/step_connect_ssh.go
builder/digitalocean/step_connect_ssh.go
+118
-0
builder/digitalocean/step_create_droplet.go
builder/digitalocean/step_create_droplet.go
+60
-0
builder/digitalocean/step_create_ssh_key.go
builder/digitalocean/step_create_ssh_key.go
+1
-1
builder/digitalocean/step_droplet_info.go
builder/digitalocean/step_droplet_info.go
+85
-0
No files found.
builder/digitalocean/api.go
View file @
dd6e4e49
...
...
@@ -103,19 +103,20 @@ func (d DigitalOceanClient) CreateSnapshot(id uint, name string) error {
}
// Returns DO's string representation of status "off" "new" "active" etc.
func
(
d
DigitalOceanClient
)
DropletStatus
(
id
uint
)
(
string
,
error
)
{
func
(
d
DigitalOceanClient
)
DropletStatus
(
id
uint
)
(
string
,
string
,
error
)
{
path
:=
fmt
.
Sprintf
(
"droplets/%s"
,
id
)
body
,
err
:=
NewRequest
(
d
,
path
,
""
)
if
err
!=
nil
{
return
""
,
err
return
""
,
""
,
err
}
// Read the droplet's "status"
droplet
:=
body
[
"droplet"
]
.
(
map
[
string
]
interface
{})
status
:=
droplet
[
"status"
]
.
(
string
)
ip
:=
droplet
[
"ip_address"
]
.
(
string
)
return
status
,
err
return
ip
,
status
,
err
}
// Sends an api request and returns a generic map[string]interface of
...
...
builder/digitalocean/builder.go
View file @
dd6e4e49
...
...
@@ -126,6 +126,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
steps
:=
[]
multistep
.
Step
{
new
(
stepCreateSSHKey
),
new
(
stepCreateDroplet
),
new
(
stepDropletInfo
),
new
(
stepConnectSSH
),
new
(
stepProvision
),
new
(
stepPowerOff
),
...
...
builder/digitalocean/step_connect_ssh.go
0 → 100644
View file @
dd6e4e49
package
digitalocean
import
(
gossh
"code.google.com/p/go.crypto/ssh"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh"
"github.com/mitchellh/packer/packer"
"log"
"net"
"time"
)
type
stepConnectSSH
struct
{
conn
net
.
Conn
}
func
(
s
*
stepConnectSSH
)
Run
(
state
map
[
string
]
interface
{})
multistep
.
StepAction
{
config
:=
state
[
"config"
]
.
(
config
)
client
:=
state
[
"client"
]
.
(
*
DigitalOceanClient
)
privateKey
:=
state
[
"privateKey"
]
.
(
string
)
ui
:=
state
[
"ui"
]
.
(
packer
.
Ui
)
ipAddress
:=
state
[
"droplet_ip"
]
// Build the keyring for authentication. This stores the private key
// we'll use to authenticate.
keyring
:=
&
ssh
.
SimpleKeychain
{}
err
:=
keyring
.
AddPEMKey
(
privateKey
)
if
err
!=
nil
{
ui
.
Say
(
fmt
.
Sprintf
(
"Error setting up SSH config: %s"
,
err
))
return
multistep
.
ActionHalt
}
// Build the actual SSH client configuration
sshConfig
:=
&
gossh
.
ClientConfig
{
User
:
config
.
SSHUsername
,
Auth
:
[]
gossh
.
ClientAuth
{
gossh
.
ClientAuthKeyring
(
keyring
),
},
}
// Start trying to connect to SSH
connected
:=
make
(
chan
bool
,
1
)
connectQuit
:=
make
(
chan
bool
,
1
)
defer
func
()
{
connectQuit
<-
true
}()
go
func
()
{
var
err
error
ui
.
Say
(
"Connecting to the droplet via SSH..."
)
attempts
:=
0
for
{
select
{
case
<-
connectQuit
:
return
default
:
}
attempts
+=
1
log
.
Printf
(
"Opening TCP conn for SSH to %s:%d (attempt %d)"
,
ipAddress
,
config
.
SSHPort
,
attempts
)
s
.
conn
,
err
=
net
.
Dial
(
"tcp"
,
fmt
.
Sprintf
(
"%s:%d"
,
ipAddress
,
config
.
SSHPort
))
if
err
==
nil
{
break
}
// A brief sleep so we're not being overly zealous attempting
// to connect to the instance.
time
.
Sleep
(
500
*
time
.
Millisecond
)
}
connected
<-
true
}()
log
.
Printf
(
"Waiting up to %s for SSH connection"
,
config
.
SSHTimeout
)
timeout
:=
time
.
After
(
config
.
SSHTimeout
)
ConnectWaitLoop
:
for
{
select
{
case
<-
connected
:
// We connected. Just break the loop.
break
ConnectWaitLoop
case
<-
timeout
:
ui
.
Error
(
"Timeout while waiting to connect to SSH."
)
return
multistep
.
ActionHalt
case
<-
time
.
After
(
1
*
time
.
Second
)
:
if
_
,
ok
:=
state
[
multistep
.
StateCancelled
];
ok
{
log
.
Println
(
"Interrupt detected, quitting waiting for SSH."
)
return
multistep
.
ActionHalt
}
}
}
var
comm
packer
.
Communicator
if
err
==
nil
{
comm
,
err
=
ssh
.
New
(
s
.
conn
,
sshConfig
)
}
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error connecting to SSH: %s"
,
err
))
return
multistep
.
ActionHalt
}
// Set the communicator on the state bag so it can be used later
state
[
"communicator"
]
=
comm
return
multistep
.
ActionContinue
}
func
(
s
*
stepConnectSSH
)
Cleanup
(
map
[
string
]
interface
{})
{
if
s
.
conn
!=
nil
{
s
.
conn
.
Close
()
}
}
builder/digitalocean/step_create_droplet.go
0 → 100644
View file @
dd6e4e49
package
digitalocean
import
(
"cgl.tideland.biz/identifier"
"encoding/hex"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type
stepCreateDroplet
struct
{
dropletId
uint
}
func
(
s
*
stepCreateDroplet
)
Run
(
state
map
[
string
]
interface
{})
multistep
.
StepAction
{
client
:=
state
[
"client"
]
.
(
*
DigitalOceanClient
)
ui
:=
state
[
"ui"
]
.
(
packer
.
Ui
)
c
:=
state
[
"config"
]
.
(
config
)
sshKeyId
:=
state
[
"ssh_key_id"
]
.
(
uint
)
ui
.
Say
(
"Creating droplet..."
)
// Some random droplet name as it's temporary
name
:=
fmt
.
Sprintf
(
"packer-%s"
,
hex
.
EncodeToString
(
identifier
.
NewUUID
()
.
Raw
()))
// Create the droplet based on configuration
dropletId
,
err
:=
client
.
CreateDroplet
(
name
,
c
.
SizeID
,
c
.
ImageID
,
c
.
RegionID
,
sshKeyId
)
if
err
!=
nil
{
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
}
// We use this in cleanup
s
.
dropletId
=
dropletId
// Store the droplet id for later
state
[
"droplet_id"
]
=
dropletId
return
multistep
.
ActionContinue
}
func
(
s
*
stepCreateDroplet
)
Cleanup
(
state
map
[
string
]
interface
{})
{
// If the dropletid isn't there, we probably never created it
if
s
.
dropletId
==
0
{
return
}
client
:=
state
[
"client"
]
.
(
*
DigitalOceanClient
)
ui
:=
state
[
"ui"
]
.
(
packer
.
Ui
)
// Destroy the droplet we just created
ui
.
Say
(
"Destroying droplet..."
)
err
:=
client
.
DestroyDroplet
(
s
.
dropletId
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error destroying droplet. Please destroy it manually: %s"
,
s
.
dropletId
))
}
}
builder/digitalocean/step_create_ssh_key.go
View file @
dd6e4e49
...
...
@@ -65,7 +65,7 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
log
.
Printf
(
"temporary ssh key name: %s"
,
name
)
// Remember some state for the future
state
[
"
keyI
d"
]
=
keyId
state
[
"
ssh_key_i
d"
]
=
keyId
state
[
"privateKey"
]
=
string
(
pem
.
EncodeToMemory
(
&
priv_blk
))
return
multistep
.
ActionContinue
...
...
builder/digitalocean/step_droplet_info.go
0 → 100644
View file @
dd6e4e49
package
digitalocean
import
(
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"time"
)
type
stepDropletInfo
struct
{}
func
(
s
*
stepDropletInfo
)
Run
(
state
map
[
string
]
interface
{})
multistep
.
StepAction
{
client
:=
state
[
"client"
]
.
(
*
DigitalOceanClient
)
ui
:=
state
[
"ui"
]
.
(
packer
.
Ui
)
c
:=
state
[
"config"
]
.
(
config
)
dropletId
:=
state
[
"droplet_id"
]
.
(
uint
)
ui
.
Say
(
"Waiting for droplet to become active..."
)
// Wait for the droplet to become active
active
:=
make
(
chan
bool
,
1
)
go
func
()
{
var
err
error
attempts
:=
0
for
{
select
{
default
:
}
attempts
+=
1
log
.
Printf
(
"Checking droplet status... (attempt: %d)"
,
attempts
)
ip
,
status
,
err
:=
client
.
DropletStatus
(
dropletId
)
if
status
==
"active"
{
break
}
// Wait a second in between
time
.
Sleep
(
1
*
time
.
Second
)
}
active
<-
true
}()
log
.
Printf
(
"Waiting for up to 3 minutes for droplet to become active"
)
duration
,
_
:=
time
.
ParseDuration
(
"3m"
)
timeout
:=
time
.
After
(
duration
)
ActiveWaitLoop
:
for
{
select
{
case
<-
active
:
// We connected. Just break the loop.
break
ActiveWaitLoop
case
<-
timeout
:
ui
.
Error
(
"Timeout while waiting to for droplet to become active"
)
return
multistep
.
ActionHalt
case
<-
time
.
After
(
1
*
time
.
Second
)
:
if
_
,
ok
:=
state
[
multistep
.
StateCancelled
];
ok
{
log
.
Println
(
"Interrupt detected, quitting waiting droplet to become active"
)
return
multistep
.
ActionHalt
}
}
}
// Set the IP on the state for later
ip
,
_
,
err
:=
client
.
DropletStatus
(
dropletId
)
if
err
!=
nil
{
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
}
state
[
"droplet_ip"
]
=
ip
return
multistep
.
ActionContinue
}
func
(
s
*
stepDropletInfo
)
Cleanup
(
state
map
[
string
]
interface
{})
{
// no cleanup
}
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