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
a0d41fcd
Commit
a0d41fcd
authored
Jun 12, 2015
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
builder/openstack
parent
46f518f2
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
294 additions
and
1547 deletions
+294
-1547
builder/openstack-new/access_config.go
builder/openstack-new/access_config.go
+0
-109
builder/openstack-new/artifact.go
builder/openstack-new/artifact.go
+0
-47
builder/openstack-new/artifact_test.go
builder/openstack-new/artifact_test.go
+0
-35
builder/openstack-new/builder.go
builder/openstack-new/builder.go
+0
-134
builder/openstack-new/builder_test.go
builder/openstack-new/builder_test.go
+0
-94
builder/openstack-new/image_config.go
builder/openstack-new/image_config.go
+0
-25
builder/openstack-new/image_config_test.go
builder/openstack-new/image_config_test.go
+0
-23
builder/openstack-new/run_config.go
builder/openstack-new/run_config.go
+0
-75
builder/openstack-new/run_config_test.go
builder/openstack-new/run_config_test.go
+0
-88
builder/openstack-new/server.go
builder/openstack-new/server.go
+0
-95
builder/openstack-new/ssh.go
builder/openstack-new/ssh.go
+0
-92
builder/openstack-new/step_allocate_ip.go
builder/openstack-new/step_allocate_ip.go
+0
-93
builder/openstack-new/step_create_image.go
builder/openstack-new/step_create_image.go
+0
-84
builder/openstack-new/step_key_pair.go
builder/openstack-new/step_key_pair.go
+0
-106
builder/openstack-new/step_run_source_server.go
builder/openstack-new/step_run_source_server.go
+0
-110
builder/openstack-new/step_wait_for_rackconnect.go
builder/openstack-new/step_wait_for_rackconnect.go
+0
-52
builder/openstack/access_config.go
builder/openstack/access_config.go
+75
-68
builder/openstack/access_config_test.go
builder/openstack/access_config_test.go
+0
-77
builder/openstack/artifact.go
builder/openstack/artifact.go
+4
-3
builder/openstack/builder.go
builder/openstack/builder.go
+4
-19
builder/openstack/server.go
builder/openstack/server.go
+12
-11
builder/openstack/ssh.go
builder/openstack/ssh.go
+40
-22
builder/openstack/step_allocate_ip.go
builder/openstack/step_allocate_ip.go
+47
-21
builder/openstack/step_create_image.go
builder/openstack/step_create_image.go
+27
-12
builder/openstack/step_key_pair.go
builder/openstack/step_key_pair.go
+30
-13
builder/openstack/step_run_source_server.go
builder/openstack/step_run_source_server.go
+40
-32
builder/openstack/step_wait_for_rackconnect.go
builder/openstack/step_wait_for_rackconnect.go
+15
-7
No files found.
builder/openstack-new/access_config.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"crypto/tls"
"fmt"
"net/http"
"os"
"github.com/mitchellh/packer/template/interpolate"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack"
)
// AccessConfig is for common configuration related to openstack access
type
AccessConfig
struct
{
Username
string
`mapstructure:"username"`
UserID
string
`mapstructure:"user_id"`
Password
string
`mapstructure:"password"`
APIKey
string
`mapstructure:"api_key"`
IdentityEndpoint
string
`mapstructure:"identity_endpoint"`
TenantID
string
`mapstructure:"tenant_id"`
TenantName
string
`mapstructure:"tenant_name"`
DomainID
string
`mapstructure:"domain_id"`
DomainName
string
`mapstructure:"domain_name"`
Insecure
bool
`mapstructure:"insecure"`
Region
string
`mapstructure:"region"`
EndpointType
string
`mapstructure:"endpoint_type"`
osClient
*
gophercloud
.
ProviderClient
}
func
(
c
*
AccessConfig
)
Prepare
(
ctx
*
interpolate
.
Context
)
[]
error
{
if
c
.
EndpointType
!=
"internal"
&&
c
.
EndpointType
!=
"internalURL"
&&
c
.
EndpointType
!=
"admin"
&&
c
.
EndpointType
!=
"adminURL"
&&
c
.
EndpointType
!=
"public"
&&
c
.
EndpointType
!=
"publicURL"
&&
c
.
EndpointType
!=
""
{
return
[]
error
{
fmt
.
Errorf
(
"Invalid endpoint type provided"
)}
}
if
c
.
Region
==
""
{
c
.
Region
=
os
.
Getenv
(
"OS_REGION_NAME"
)
}
// Get as much as possible from the end
ao
,
err
:=
openstack
.
AuthOptionsFromEnv
()
if
err
!=
nil
{
return
[]
error
{
err
}
}
// Override values if we have them in our config
overrides
:=
[]
struct
{
From
,
To
*
string
}{
{
&
c
.
Username
,
&
ao
.
Username
},
{
&
c
.
UserID
,
&
ao
.
UserID
},
{
&
c
.
Password
,
&
ao
.
Password
},
{
&
c
.
APIKey
,
&
ao
.
APIKey
},
{
&
c
.
IdentityEndpoint
,
&
ao
.
IdentityEndpoint
},
{
&
c
.
TenantID
,
&
ao
.
TenantID
},
{
&
c
.
TenantName
,
&
ao
.
TenantName
},
{
&
c
.
DomainID
,
&
ao
.
DomainID
},
{
&
c
.
DomainName
,
&
ao
.
DomainName
},
}
for
_
,
s
:=
range
overrides
{
if
*
s
.
From
!=
""
{
*
s
.
To
=
*
s
.
From
}
}
// Build the client itself
client
,
err
:=
openstack
.
NewClient
(
ao
.
IdentityEndpoint
)
if
err
!=
nil
{
return
[]
error
{
err
}
}
// If we have insecure set, then create a custom HTTP client that
// ignores SSL errors.
if
c
.
Insecure
{
config
:=
&
tls
.
Config
{
InsecureSkipVerify
:
true
}
transport
:=
&
http
.
Transport
{
TLSClientConfig
:
config
}
client
.
HTTPClient
.
Transport
=
transport
}
// Auth
err
=
openstack
.
Authenticate
(
client
,
ao
)
if
err
!=
nil
{
return
[]
error
{
err
}
}
c
.
osClient
=
client
return
nil
}
func
(
c
*
AccessConfig
)
computeV2Client
()
(
*
gophercloud
.
ServiceClient
,
error
)
{
return
openstack
.
NewComputeV2
(
c
.
osClient
,
gophercloud
.
EndpointOpts
{
Region
:
c
.
Region
,
Availability
:
c
.
getEndpointType
(),
})
}
func
(
c
*
AccessConfig
)
getEndpointType
()
gophercloud
.
Availability
{
if
c
.
EndpointType
==
"internal"
||
c
.
EndpointType
==
"internalURL"
{
return
gophercloud
.
AvailabilityInternal
}
if
c
.
EndpointType
==
"admin"
||
c
.
EndpointType
==
"adminURL"
{
return
gophercloud
.
AvailabilityAdmin
}
return
gophercloud
.
AvailabilityPublic
}
builder/openstack-new/artifact.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"fmt"
"log"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/images"
)
// Artifact is an artifact implementation that contains built images.
type
Artifact
struct
{
// ImageId of built image
ImageId
string
// BuilderId is the unique ID for the builder that created this image
BuilderIdValue
string
// OpenStack connection for performing API stuff.
Client
*
gophercloud
.
ServiceClient
}
func
(
a
*
Artifact
)
BuilderId
()
string
{
return
a
.
BuilderIdValue
}
func
(
*
Artifact
)
Files
()
[]
string
{
// We have no files
return
nil
}
func
(
a
*
Artifact
)
Id
()
string
{
return
a
.
ImageId
}
func
(
a
*
Artifact
)
String
()
string
{
return
fmt
.
Sprintf
(
"An image was created: %v"
,
a
.
ImageId
)
}
func
(
a
*
Artifact
)
State
(
name
string
)
interface
{}
{
return
nil
}
func
(
a
*
Artifact
)
Destroy
()
error
{
log
.
Printf
(
"Destroying image: %s"
,
a
.
ImageId
)
return
images
.
Delete
(
a
.
Client
,
a
.
ImageId
)
.
ExtractErr
()
}
builder/openstack-new/artifact_test.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"github.com/mitchellh/packer/packer"
"testing"
)
func
TestArtifact_Impl
(
t
*
testing
.
T
)
{
var
_
packer
.
Artifact
=
new
(
Artifact
)
}
func
TestArtifactId
(
t
*
testing
.
T
)
{
expected
:=
`b8cdf55b-c916-40bd-b190-389ec144c4ed`
a
:=
&
Artifact
{
ImageId
:
"b8cdf55b-c916-40bd-b190-389ec144c4ed"
,
}
result
:=
a
.
Id
()
if
result
!=
expected
{
t
.
Fatalf
(
"bad: %s"
,
result
)
}
}
func
TestArtifactString
(
t
*
testing
.
T
)
{
expected
:=
"An image was created: b8cdf55b-c916-40bd-b190-389ec144c4ed"
a
:=
&
Artifact
{
ImageId
:
"b8cdf55b-c916-40bd-b190-389ec144c4ed"
,
}
result
:=
a
.
String
()
if
result
!=
expected
{
t
.
Fatalf
(
"bad: %s"
,
result
)
}
}
builder/openstack-new/builder.go
deleted
100644 → 0
View file @
46f518f2
// The openstack package contains a packer.Builder implementation that
// builds Images for openstack.
package
openstack
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common"
"log"
"github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
)
// The unique ID for this builder
const
BuilderId
=
"mitchellh.openstack"
type
Config
struct
{
common
.
PackerConfig
`mapstructure:",squash"`
AccessConfig
`mapstructure:",squash"`
ImageConfig
`mapstructure:",squash"`
RunConfig
`mapstructure:",squash"`
ctx
interpolate
.
Context
}
type
Builder
struct
{
config
Config
runner
multistep
.
Runner
}
func
(
b
*
Builder
)
Prepare
(
raws
...
interface
{})
([]
string
,
error
)
{
err
:=
config
.
Decode
(
&
b
.
config
,
&
config
.
DecodeOpts
{
Interpolate
:
true
,
},
raws
...
)
if
err
!=
nil
{
return
nil
,
err
}
// Accumulate any errors
var
errs
*
packer
.
MultiError
errs
=
packer
.
MultiErrorAppend
(
errs
,
b
.
config
.
AccessConfig
.
Prepare
(
&
b
.
config
.
ctx
)
...
)
errs
=
packer
.
MultiErrorAppend
(
errs
,
b
.
config
.
ImageConfig
.
Prepare
(
&
b
.
config
.
ctx
)
...
)
errs
=
packer
.
MultiErrorAppend
(
errs
,
b
.
config
.
RunConfig
.
Prepare
(
&
b
.
config
.
ctx
)
...
)
if
errs
!=
nil
&&
len
(
errs
.
Errors
)
>
0
{
return
nil
,
errs
}
log
.
Println
(
common
.
ScrubConfig
(
b
.
config
,
b
.
config
.
Password
))
return
nil
,
nil
}
func
(
b
*
Builder
)
Run
(
ui
packer
.
Ui
,
hook
packer
.
Hook
,
cache
packer
.
Cache
)
(
packer
.
Artifact
,
error
)
{
computeClient
,
err
:=
b
.
config
.
computeV2Client
()
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
}
// Setup the state bag and initial state for the steps
state
:=
new
(
multistep
.
BasicStateBag
)
state
.
Put
(
"config"
,
b
.
config
)
state
.
Put
(
"hook"
,
hook
)
state
.
Put
(
"ui"
,
ui
)
// Build the steps
steps
:=
[]
multistep
.
Step
{
&
StepKeyPair
{
Debug
:
b
.
config
.
PackerDebug
,
DebugKeyPath
:
fmt
.
Sprintf
(
"os_%s.pem"
,
b
.
config
.
PackerBuildName
),
},
&
StepRunSourceServer
{
Name
:
b
.
config
.
ImageName
,
Flavor
:
b
.
config
.
Flavor
,
SourceImage
:
b
.
config
.
SourceImage
,
SecurityGroups
:
b
.
config
.
SecurityGroups
,
Networks
:
b
.
config
.
Networks
,
},
&
StepWaitForRackConnect
{
Wait
:
b
.
config
.
RackconnectWait
,
},
&
StepAllocateIp
{
FloatingIpPool
:
b
.
config
.
FloatingIpPool
,
FloatingIp
:
b
.
config
.
FloatingIp
,
},
&
common
.
StepConnectSSH
{
SSHAddress
:
SSHAddress
(
computeClient
,
b
.
config
.
SSHInterface
,
b
.
config
.
SSHPort
),
SSHConfig
:
SSHConfig
(
b
.
config
.
SSHUsername
),
SSHWaitTimeout
:
b
.
config
.
SSHTimeout
(),
},
&
common
.
StepProvision
{},
&
stepCreateImage
{},
}
// Run!
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 there was an error, return that
if
rawErr
,
ok
:=
state
.
GetOk
(
"error"
);
ok
{
return
nil
,
rawErr
.
(
error
)
}
// If there are no images, then just return
if
_
,
ok
:=
state
.
GetOk
(
"image"
);
!
ok
{
return
nil
,
nil
}
// Build the artifact and return it
artifact
:=
&
Artifact
{
ImageId
:
state
.
Get
(
"image"
)
.
(
string
),
BuilderIdValue
:
BuilderId
,
Client
:
computeClient
,
}
return
artifact
,
nil
}
func
(
b
*
Builder
)
Cancel
()
{
if
b
.
runner
!=
nil
{
log
.
Println
(
"Cancelling the step runner..."
)
b
.
runner
.
Cancel
()
}
}
builder/openstack-new/builder_test.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"github.com/mitchellh/packer/packer"
"testing"
)
func
testConfig
()
map
[
string
]
interface
{}
{
return
map
[
string
]
interface
{}{
"username"
:
"foo"
,
"password"
:
"bar"
,
"provider"
:
"foo"
,
"region"
:
"DFW"
,
"image_name"
:
"foo"
,
"source_image"
:
"foo"
,
"flavor"
:
"foo"
,
"ssh_username"
:
"root"
,
}
}
func
TestBuilder_ImplementsBuilder
(
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
{}{
"password"
:
[]
string
{},
}
warns
,
err
:=
b
.
Prepare
(
c
)
if
len
(
warns
)
>
0
{
t
.
Fatalf
(
"bad: %#v"
,
warns
)
}
if
err
==
nil
{
t
.
Fatalf
(
"prepare should fail"
)
}
}
func
TestBuilderPrepare_ImageName
(
t
*
testing
.
T
)
{
var
b
Builder
config
:=
testConfig
()
// Test good
config
[
"image_name"
]
=
"foo"
warns
,
err
:=
b
.
Prepare
(
config
)
if
len
(
warns
)
>
0
{
t
.
Fatalf
(
"bad: %#v"
,
warns
)
}
if
err
!=
nil
{
t
.
Fatalf
(
"should not have error: %s"
,
err
)
}
// Test bad
config
[
"image_name"
]
=
"foo {{"
b
=
Builder
{}
warns
,
err
=
b
.
Prepare
(
config
)
if
len
(
warns
)
>
0
{
t
.
Fatalf
(
"bad: %#v"
,
warns
)
}
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
// Test bad
delete
(
config
,
"image_name"
)
b
=
Builder
{}
warns
,
err
=
b
.
Prepare
(
config
)
if
len
(
warns
)
>
0
{
t
.
Fatalf
(
"bad: %#v"
,
warns
)
}
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
}
func
TestBuilderPrepare_InvalidKey
(
t
*
testing
.
T
)
{
var
b
Builder
config
:=
testConfig
()
// Add a random key
config
[
"i_should_not_be_valid"
]
=
true
warns
,
err
:=
b
.
Prepare
(
config
)
if
len
(
warns
)
>
0
{
t
.
Fatalf
(
"bad: %#v"
,
warns
)
}
if
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
}
builder/openstack-new/image_config.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"fmt"
"github.com/mitchellh/packer/template/interpolate"
)
// ImageConfig is for common configuration related to creating Images.
type
ImageConfig
struct
{
ImageName
string
`mapstructure:"image_name"`
}
func
(
c
*
ImageConfig
)
Prepare
(
ctx
*
interpolate
.
Context
)
[]
error
{
errs
:=
make
([]
error
,
0
)
if
c
.
ImageName
==
""
{
errs
=
append
(
errs
,
fmt
.
Errorf
(
"An image_name must be specified"
))
}
if
len
(
errs
)
>
0
{
return
errs
}
return
nil
}
builder/openstack-new/image_config_test.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"testing"
)
func
testImageConfig
()
*
ImageConfig
{
return
&
ImageConfig
{
ImageName
:
"foo"
,
}
}
func
TestImageConfigPrepare_Region
(
t
*
testing
.
T
)
{
c
:=
testImageConfig
()
if
err
:=
c
.
Prepare
(
nil
);
err
!=
nil
{
t
.
Fatalf
(
"shouldn't have err: %s"
,
err
)
}
c
.
ImageName
=
""
if
err
:=
c
.
Prepare
(
nil
);
err
==
nil
{
t
.
Fatal
(
"should have error"
)
}
}
builder/openstack-new/run_config.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"errors"
"fmt"
"time"
"github.com/mitchellh/packer/template/interpolate"
)
// RunConfig contains configuration for running an instance from a source
// image and details on how to access that launched image.
type
RunConfig
struct
{
SourceImage
string
`mapstructure:"source_image"`
Flavor
string
`mapstructure:"flavor"`
RawSSHTimeout
string
`mapstructure:"ssh_timeout"`
SSHUsername
string
`mapstructure:"ssh_username"`
SSHPort
int
`mapstructure:"ssh_port"`
SSHInterface
string
`mapstructure:"ssh_interface"`
OpenstackProvider
string
`mapstructure:"openstack_provider"`
UseFloatingIp
bool
`mapstructure:"use_floating_ip"`
RackconnectWait
bool
`mapstructure:"rackconnect_wait"`
FloatingIpPool
string
`mapstructure:"floating_ip_pool"`
FloatingIp
string
`mapstructure:"floating_ip"`
SecurityGroups
[]
string
`mapstructure:"security_groups"`
Networks
[]
string
`mapstructure:"networks"`
// Unexported fields that are calculated from others
sshTimeout
time
.
Duration
}
func
(
c
*
RunConfig
)
Prepare
(
ctx
*
interpolate
.
Context
)
[]
error
{
// Defaults
if
c
.
SSHUsername
==
""
{
c
.
SSHUsername
=
"root"
}
if
c
.
SSHPort
==
0
{
c
.
SSHPort
=
22
}
if
c
.
RawSSHTimeout
==
""
{
c
.
RawSSHTimeout
=
"5m"
}
if
c
.
UseFloatingIp
&&
c
.
FloatingIpPool
==
""
{
c
.
FloatingIpPool
=
"public"
}
// Validation
var
err
error
errs
:=
make
([]
error
,
0
)
if
c
.
SourceImage
==
""
{
errs
=
append
(
errs
,
errors
.
New
(
"A source_image must be specified"
))
}
if
c
.
Flavor
==
""
{
errs
=
append
(
errs
,
errors
.
New
(
"A flavor must be specified"
))
}
if
c
.
SSHUsername
==
""
{
errs
=
append
(
errs
,
errors
.
New
(
"An ssh_username must be specified"
))
}
c
.
sshTimeout
,
err
=
time
.
ParseDuration
(
c
.
RawSSHTimeout
)
if
err
!=
nil
{
errs
=
append
(
errs
,
fmt
.
Errorf
(
"Failed parsing ssh_timeout: %s"
,
err
))
}
return
errs
}
func
(
c
*
RunConfig
)
SSHTimeout
()
time
.
Duration
{
return
c
.
sshTimeout
}
builder/openstack-new/run_config_test.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"os"
"testing"
)
func
init
()
{
// Clear out the openstack env vars so they don't
// affect our tests.
os
.
Setenv
(
"SDK_USERNAME"
,
""
)
os
.
Setenv
(
"SDK_PASSWORD"
,
""
)
os
.
Setenv
(
"SDK_PROVIDER"
,
""
)
}
func
testRunConfig
()
*
RunConfig
{
return
&
RunConfig
{
SourceImage
:
"abcd"
,
Flavor
:
"m1.small"
,
SSHUsername
:
"root"
,
}
}
func
TestRunConfigPrepare
(
t
*
testing
.
T
)
{
c
:=
testRunConfig
()
err
:=
c
.
Prepare
(
nil
)
if
len
(
err
)
>
0
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
}
func
TestRunConfigPrepare_InstanceType
(
t
*
testing
.
T
)
{
c
:=
testRunConfig
()
c
.
Flavor
=
""
if
err
:=
c
.
Prepare
(
nil
);
len
(
err
)
!=
1
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
}
func
TestRunConfigPrepare_SourceImage
(
t
*
testing
.
T
)
{
c
:=
testRunConfig
()
c
.
SourceImage
=
""
if
err
:=
c
.
Prepare
(
nil
);
len
(
err
)
!=
1
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
}
func
TestRunConfigPrepare_SSHPort
(
t
*
testing
.
T
)
{
c
:=
testRunConfig
()
c
.
SSHPort
=
0
if
err
:=
c
.
Prepare
(
nil
);
len
(
err
)
!=
0
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
if
c
.
SSHPort
!=
22
{
t
.
Fatalf
(
"invalid value: %d"
,
c
.
SSHPort
)
}
c
.
SSHPort
=
44
if
err
:=
c
.
Prepare
(
nil
);
len
(
err
)
!=
0
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
if
c
.
SSHPort
!=
44
{
t
.
Fatalf
(
"invalid value: %d"
,
c
.
SSHPort
)
}
}
func
TestRunConfigPrepare_SSHTimeout
(
t
*
testing
.
T
)
{
c
:=
testRunConfig
()
c
.
RawSSHTimeout
=
""
if
err
:=
c
.
Prepare
(
nil
);
len
(
err
)
!=
0
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
c
.
RawSSHTimeout
=
"bad"
if
err
:=
c
.
Prepare
(
nil
);
len
(
err
)
!=
1
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
}
func
TestRunConfigPrepare_SSHUsername
(
t
*
testing
.
T
)
{
c
:=
testRunConfig
()
c
.
SSHUsername
=
""
if
err
:=
c
.
Prepare
(
nil
);
len
(
err
)
!=
0
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
}
builder/openstack-new/server.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"errors"
"fmt"
"log"
"time"
"github.com/mitchellh/multistep"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
// StateRefreshFunc is a function type used for StateChangeConf that is
// responsible for refreshing the item being watched for a state change.
//
// It returns three results. `result` is any object that will be returned
// as the final object after waiting for state change. This allows you to
// return the final updated object, for example an openstack instance after
// refreshing it.
//
// `state` is the latest state of that object. And `err` is any error that
// may have happened while refreshing the state.
type
StateRefreshFunc
func
()
(
result
interface
{},
state
string
,
progress
int
,
err
error
)
// StateChangeConf is the configuration struct used for `WaitForState`.
type
StateChangeConf
struct
{
Pending
[]
string
Refresh
StateRefreshFunc
StepState
multistep
.
StateBag
Target
string
}
// ServerStateRefreshFunc returns a StateRefreshFunc that is used to watch
// an openstack server.
func
ServerStateRefreshFunc
(
client
*
gophercloud
.
ServiceClient
,
s
*
servers
.
Server
)
StateRefreshFunc
{
return
func
()
(
interface
{},
string
,
int
,
error
)
{
serverNew
,
err
:=
servers
.
Get
(
client
,
s
.
ID
)
.
Extract
()
if
err
!=
nil
{
errCode
,
ok
:=
err
.
(
*
gophercloud
.
UnexpectedResponseCodeError
)
if
ok
&&
errCode
.
Actual
==
404
{
log
.
Printf
(
"[INFO] 404 on ServerStateRefresh, returning DELETED"
)
return
nil
,
"DELETED"
,
0
,
nil
}
else
{
log
.
Printf
(
"[ERROR] Error on ServerStateRefresh: %s"
,
err
)
return
nil
,
""
,
0
,
err
}
}
return
serverNew
,
serverNew
.
Status
,
serverNew
.
Progress
,
nil
}
}
// WaitForState watches an object and waits for it to achieve a certain
// state.
func
WaitForState
(
conf
*
StateChangeConf
)
(
i
interface
{},
err
error
)
{
log
.
Printf
(
"Waiting for state to become: %s"
,
conf
.
Target
)
for
{
var
currentProgress
int
var
currentState
string
i
,
currentState
,
currentProgress
,
err
=
conf
.
Refresh
()
if
err
!=
nil
{
return
}
if
currentState
==
conf
.
Target
{
return
}
if
conf
.
StepState
!=
nil
{
if
_
,
ok
:=
conf
.
StepState
.
GetOk
(
multistep
.
StateCancelled
);
ok
{
return
nil
,
errors
.
New
(
"interrupted"
)
}
}
found
:=
false
for
_
,
allowed
:=
range
conf
.
Pending
{
if
currentState
==
allowed
{
found
=
true
break
}
}
if
!
found
{
return
nil
,
fmt
.
Errorf
(
"unexpected state '%s', wanted target '%s'"
,
currentState
,
conf
.
Target
)
}
log
.
Printf
(
"Waiting for state to become: %s currently %s (%d%%)"
,
conf
.
Target
,
currentState
,
currentProgress
)
time
.
Sleep
(
2
*
time
.
Second
)
}
return
}
builder/openstack-new/ssh.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"errors"
"fmt"
"log"
"time"
"github.com/mitchellh/multistep"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
"golang.org/x/crypto/ssh"
)
// SSHAddress returns a function that can be given to the SSH communicator
// for determining the SSH address based on the server AccessIPv4 setting..
func
SSHAddress
(
client
*
gophercloud
.
ServiceClient
,
sshinterface
string
,
port
int
)
func
(
multistep
.
StateBag
)
(
string
,
error
)
{
return
func
(
state
multistep
.
StateBag
)
(
string
,
error
)
{
s
:=
state
.
Get
(
"server"
)
.
(
*
servers
.
Server
)
// If we have a floating IP, use that
ip
:=
state
.
Get
(
"access_ip"
)
.
(
*
floatingip
.
FloatingIP
)
if
ip
!=
nil
&&
ip
.
FixedIP
!=
""
{
return
fmt
.
Sprintf
(
"%s:%d"
,
ip
.
FixedIP
,
port
),
nil
}
if
s
.
AccessIPv4
!=
""
{
return
fmt
.
Sprintf
(
"%s:%d"
,
s
.
AccessIPv4
,
port
),
nil
}
// Get all the addresses associated with this server. This
// was taken directly from Terraform.
for
_
,
networkAddresses
:=
range
s
.
Addresses
{
elements
,
ok
:=
networkAddresses
.
([]
interface
{})
if
!
ok
{
log
.
Printf
(
"[ERROR] Unknown return type for address field: %#v"
,
networkAddresses
)
continue
}
for
_
,
element
:=
range
elements
{
var
addr
string
address
:=
element
.
(
map
[
string
]
interface
{})
if
address
[
"OS-EXT-IPS:type"
]
==
"floating"
{
addr
=
address
[
"addr"
]
.
(
string
)
}
else
{
if
address
[
"version"
]
.
(
float64
)
==
4
{
addr
=
address
[
"addr"
]
.
(
string
)
}
}
if
addr
!=
""
{
return
fmt
.
Sprintf
(
"%s:%d"
,
addr
,
port
),
nil
}
}
}
s
,
err
:=
servers
.
Get
(
client
,
s
.
ID
)
.
Extract
()
if
err
!=
nil
{
return
""
,
err
}
state
.
Put
(
"server"
,
s
)
time
.
Sleep
(
1
*
time
.
Second
)
return
""
,
errors
.
New
(
"couldn't determine IP address for server"
)
}
}
// SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the generated
// private key.
func
SSHConfig
(
username
string
)
func
(
multistep
.
StateBag
)
(
*
ssh
.
ClientConfig
,
error
)
{
return
func
(
state
multistep
.
StateBag
)
(
*
ssh
.
ClientConfig
,
error
)
{
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
:
username
,
Auth
:
[]
ssh
.
AuthMethod
{
ssh
.
PublicKeys
(
signer
),
},
},
nil
}
}
builder/openstack-new/step_allocate_ip.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
type
StepAllocateIp
struct
{
FloatingIpPool
string
FloatingIp
string
}
func
(
s
*
StepAllocateIp
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
server
:=
state
.
Get
(
"server"
)
.
(
*
servers
.
Server
)
// We need the v2 compute client
client
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
var
instanceIp
*
floatingip
.
FloatingIP
// This is here in case we error out before putting instanceIp into the
// statebag below, because it is requested by Cleanup()
state
.
Put
(
"access_ip"
,
instanceIp
)
if
s
.
FloatingIp
!=
""
{
*
instanceIp
=
floatingip
.
FloatingIP
{
FixedIP
:
s
.
FloatingIp
}
}
else
if
s
.
FloatingIpPool
!=
""
{
newIp
,
err
:=
floatingip
.
Create
(
client
,
floatingip
.
CreateOpts
{
Pool
:
s
.
FloatingIpPool
,
})
.
Extract
()
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error creating floating ip from pool '%s'"
,
s
.
FloatingIpPool
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
}
*
instanceIp
=
*
newIp
ui
.
Say
(
fmt
.
Sprintf
(
"Created temporary floating IP %s..."
,
instanceIp
.
FixedIP
))
}
if
instanceIp
!=
nil
&&
instanceIp
.
FixedIP
!=
""
{
err
:=
floatingip
.
Associate
(
client
,
server
.
ID
,
instanceIp
.
FixedIP
)
.
ExtractErr
()
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error associating floating IP %s with instance."
,
instanceIp
.
FixedIP
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
}
ui
.
Say
(
fmt
.
Sprintf
(
"Added floating IP %s to instance..."
,
instanceIp
.
FixedIP
))
}
state
.
Put
(
"access_ip"
,
instanceIp
)
return
multistep
.
ActionContinue
}
func
(
s
*
StepAllocateIp
)
Cleanup
(
state
multistep
.
StateBag
)
{
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
instanceIp
:=
state
.
Get
(
"access_ip"
)
.
(
*
floatingip
.
FloatingIP
)
// We need the v2 compute client
client
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error deleting temporary floating IP %s"
,
instanceIp
.
FixedIP
))
return
}
if
s
.
FloatingIpPool
!=
""
&&
instanceIp
.
ID
!=
""
{
if
err
:=
floatingip
.
Delete
(
client
,
instanceIp
.
ID
)
.
ExtractErr
();
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error deleting temporary floating IP %s"
,
instanceIp
.
FixedIP
))
return
}
ui
.
Say
(
fmt
.
Sprintf
(
"Deleted temporary floating IP %s"
,
instanceIp
.
FixedIP
))
}
}
builder/openstack-new/step_create_image.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"fmt"
"log"
"time"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/images"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
type
stepCreateImage
struct
{}
func
(
s
*
stepCreateImage
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
server
:=
state
.
Get
(
"server"
)
.
(
*
servers
.
Server
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
client
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
// Create the image
ui
.
Say
(
fmt
.
Sprintf
(
"Creating the image: %s"
,
config
.
ImageName
))
imageId
,
err
:=
servers
.
CreateImage
(
client
,
server
.
ID
,
servers
.
CreateImageOpts
{
Name
:
config
.
ImageName
,
})
.
ExtractImageID
()
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error creating image: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
}
// Set the Image ID in the state
ui
.
Message
(
fmt
.
Sprintf
(
"Image: %s"
,
imageId
))
state
.
Put
(
"image"
,
imageId
)
// Wait for the image to become ready
ui
.
Say
(
"Waiting for image to become ready..."
)
if
err
:=
WaitForImage
(
client
,
imageId
);
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error waiting for image: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
}
return
multistep
.
ActionContinue
}
func
(
s
*
stepCreateImage
)
Cleanup
(
multistep
.
StateBag
)
{
// No cleanup...
}
// WaitForImage waits for the given Image ID to become ready.
func
WaitForImage
(
client
*
gophercloud
.
ServiceClient
,
imageId
string
)
error
{
for
{
image
,
err
:=
images
.
Get
(
client
,
imageId
)
.
Extract
()
if
err
!=
nil
{
errCode
,
ok
:=
err
.
(
*
gophercloud
.
UnexpectedResponseCodeError
)
if
ok
&&
errCode
.
Actual
==
500
{
log
.
Printf
(
"[ERROR] 500 error received, will ignore and retry: %s"
,
err
)
time
.
Sleep
(
2
*
time
.
Second
)
continue
}
return
err
}
if
image
.
Status
==
"ACTIVE"
{
return
nil
}
log
.
Printf
(
"Waiting for image creation status: %s (%d%%)"
,
image
.
Status
,
image
.
Progress
)
time
.
Sleep
(
2
*
time
.
Second
)
}
}
builder/openstack-new/step_key_pair.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"fmt"
"os"
"runtime"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common/uuid"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
)
type
StepKeyPair
struct
{
Debug
bool
DebugKeyPath
string
keyName
string
}
func
(
s
*
StepKeyPair
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
ui
.
Say
(
"Creating temporary keypair for this instance..."
)
keyName
:=
fmt
.
Sprintf
(
"packer %s"
,
uuid
.
TimeOrderedUUID
())
keypair
,
err
:=
keypairs
.
Create
(
computeClient
,
keypairs
.
CreateOpts
{
Name
:
keyName
,
})
.
Extract
()
if
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error creating temporary keypair: %s"
,
err
))
return
multistep
.
ActionHalt
}
if
keypair
.
PrivateKey
==
""
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"The temporary keypair returned was blank"
))
return
multistep
.
ActionHalt
}
// If we're in debug mode, output the private key to the working
// directory.
if
s
.
Debug
{
ui
.
Message
(
fmt
.
Sprintf
(
"Saving key for debug purposes: %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
}
defer
f
.
Close
()
// Write the key out
if
_
,
err
:=
f
.
Write
([]
byte
(
keypair
.
PrivateKey
));
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error saving debug key: %s"
,
err
))
return
multistep
.
ActionHalt
}
// Chmod it so that it is SSH ready
if
runtime
.
GOOS
!=
"windows"
{
if
err
:=
f
.
Chmod
(
0600
);
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error setting permissions of debug key: %s"
,
err
))
return
multistep
.
ActionHalt
}
}
}
// Set the keyname so we know to delete it later
s
.
keyName
=
keyName
// Set some state data for use in future steps
state
.
Put
(
"keyPair"
,
keyName
)
state
.
Put
(
"privateKey"
,
keypair
.
PrivateKey
)
return
multistep
.
ActionContinue
}
func
(
s
*
StepKeyPair
)
Cleanup
(
state
multistep
.
StateBag
)
{
// If no key name is set, then we never created it, so just return
if
s
.
keyName
==
""
{
return
}
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error cleaning up keypair. Please delete the key manually: %s"
,
s
.
keyName
))
return
}
ui
.
Say
(
"Deleting temporary keypair..."
)
err
=
keypairs
.
Delete
(
computeClient
,
s
.
keyName
)
.
ExtractErr
()
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error cleaning up keypair. Please delete the key manually: %s"
,
s
.
keyName
))
}
}
builder/openstack-new/step_run_source_server.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"fmt"
"log"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
type
StepRunSourceServer
struct
{
Flavor
string
Name
string
SourceImage
string
SecurityGroups
[]
string
Networks
[]
string
server
*
servers
.
Server
}
func
(
s
*
StepRunSourceServer
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
keyName
:=
state
.
Get
(
"keyPair"
)
.
(
string
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
networks
:=
make
([]
servers
.
Network
,
len
(
s
.
Networks
))
for
i
,
networkUuid
:=
range
s
.
Networks
{
networks
[
i
]
.
UUID
=
networkUuid
}
s
.
server
,
err
=
servers
.
Create
(
computeClient
,
keypairs
.
CreateOptsExt
{
CreateOptsBuilder
:
servers
.
CreateOpts
{
Name
:
s
.
Name
,
ImageRef
:
s
.
SourceImage
,
FlavorName
:
s
.
Flavor
,
SecurityGroups
:
s
.
SecurityGroups
,
Networks
:
networks
,
},
KeyName
:
keyName
,
})
.
Extract
()
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error launching source server: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
}
log
.
Printf
(
"server id: %s"
,
s
.
server
.
ID
)
ui
.
Say
(
fmt
.
Sprintf
(
"Waiting for server (%s) to become ready..."
,
s
.
server
.
ID
))
stateChange
:=
StateChangeConf
{
Pending
:
[]
string
{
"BUILD"
},
Target
:
"ACTIVE"
,
Refresh
:
ServerStateRefreshFunc
(
computeClient
,
s
.
server
),
StepState
:
state
,
}
latestServer
,
err
:=
WaitForState
(
&
stateChange
)
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error waiting for server (%s) to become ready: %s"
,
s
.
server
.
ID
,
err
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
}
s
.
server
=
latestServer
.
(
*
servers
.
Server
)
state
.
Put
(
"server"
,
s
.
server
)
return
multistep
.
ActionContinue
}
func
(
s
*
StepRunSourceServer
)
Cleanup
(
state
multistep
.
StateBag
)
{
if
s
.
server
==
nil
{
return
}
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error terminating server, may still be around: %s"
,
err
))
return
}
ui
.
Say
(
"Terminating the source server..."
)
if
err
:=
servers
.
Delete
(
computeClient
,
s
.
server
.
ID
)
.
ExtractErr
();
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error terminating server, may still be around: %s"
,
err
))
return
}
stateChange
:=
StateChangeConf
{
Pending
:
[]
string
{
"ACTIVE"
,
"BUILD"
,
"REBUILD"
,
"SUSPENDED"
},
Refresh
:
ServerStateRefreshFunc
(
computeClient
,
s
.
server
),
Target
:
"DELETED"
,
}
WaitForState
(
&
stateChange
)
}
builder/openstack-new/step_wait_for_rackconnect.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"fmt"
"time"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
type
StepWaitForRackConnect
struct
{
Wait
bool
}
func
(
s
*
StepWaitForRackConnect
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
if
!
s
.
Wait
{
return
multistep
.
ActionContinue
}
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
server
:=
state
.
Get
(
"server"
)
.
(
*
servers
.
Server
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
ui
.
Say
(
fmt
.
Sprintf
(
"Waiting for server (%s) to become RackConnect ready..."
,
server
.
ID
))
for
{
server
,
err
=
servers
.
Get
(
computeClient
,
server
.
ID
)
.
Extract
()
if
err
!=
nil
{
return
multistep
.
ActionHalt
}
if
server
.
Metadata
[
"rackconnect_automation_status"
]
==
"DEPLOYED"
{
break
}
time
.
Sleep
(
2
*
time
.
Second
)
}
return
multistep
.
ActionContinue
}
func
(
s
*
StepWaitForRackConnect
)
Cleanup
(
state
multistep
.
StateBag
)
{
}
builder/openstack/access_config.go
View file @
a0d41fcd
...
@@ -4,99 +4,106 @@ import (
...
@@ -4,99 +4,106 @@ import (
"crypto/tls"
"crypto/tls"
"fmt"
"fmt"
"net/http"
"net/http"
"net/url"
"os"
"os"
"strings"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/template/interpolate"
"github.com/mitchellh/packer/template/interpolate"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack"
)
)
// AccessConfig is for common configuration related to openstack access
// AccessConfig is for common configuration related to openstack access
type
AccessConfig
struct
{
type
AccessConfig
struct
{
Username
string
`mapstructure:"username"`
Username
string
`mapstructure:"username"`
Password
string
`mapstructure:"password"`
UserID
string
`mapstructure:"user_id"`
ApiKey
string
`mapstructure:"api_key"`
Password
string
`mapstructure:"password"`
Project
string
`mapstructure:"project"`
APIKey
string
`mapstructure:"api_key"`
Provider
string
`mapstructure:"provider"`
IdentityEndpoint
string
`mapstructure:"identity_endpoint"`
RawRegion
string
`mapstructure:"region"`
TenantID
string
`mapstructure:"tenant_id"`
ProxyUrl
string
`mapstructure:"proxy_url"`
TenantName
string
`mapstructure:"tenant_name"`
TenantId
string
`mapstructure:"tenant_id"`
DomainID
string
`mapstructure:"domain_id"`
Insecure
bool
`mapstructure:"insecure"`
DomainName
string
`mapstructure:"domain_name"`
Insecure
bool
`mapstructure:"insecure"`
Region
string
`mapstructure:"region"`
EndpointType
string
`mapstructure:"endpoint_type"`
osClient
*
gophercloud
.
ProviderClient
}
}
// Auth returns a valid Auth object for access to openstack services, or
func
(
c
*
AccessConfig
)
Prepare
(
ctx
*
interpolate
.
Context
)
[]
error
{
// an error if the authentication couldn't be resolved.
if
c
.
EndpointType
!=
"internal"
&&
c
.
EndpointType
!=
"internalURL"
&&
func
(
c
*
AccessConfig
)
Auth
()
(
gophercloud
.
AccessProvider
,
error
)
{
c
.
EndpointType
!=
"admin"
&&
c
.
EndpointType
!=
"adminURL"
&&
c
.
Username
=
common
.
ChooseString
(
c
.
Username
,
os
.
Getenv
(
"SDK_USERNAME"
),
os
.
Getenv
(
"OS_USERNAME"
))
c
.
EndpointType
!=
"public"
&&
c
.
EndpointType
!=
"publicURL"
&&
c
.
Password
=
common
.
ChooseString
(
c
.
Password
,
os
.
Getenv
(
"SDK_PASSWORD"
),
os
.
Getenv
(
"OS_PASSWORD"
))
c
.
EndpointType
!=
""
{
c
.
ApiKey
=
common
.
ChooseString
(
c
.
ApiKey
,
os
.
Getenv
(
"SDK_API_KEY"
))
return
[]
error
{
fmt
.
Errorf
(
"Invalid endpoint type provided"
)}
c
.
Project
=
common
.
ChooseString
(
c
.
Project
,
os
.
Getenv
(
"SDK_PROJECT"
),
os
.
Getenv
(
"OS_TENANT_NAME"
))
c
.
Provider
=
common
.
ChooseString
(
c
.
Provider
,
os
.
Getenv
(
"SDK_PROVIDER"
),
os
.
Getenv
(
"OS_AUTH_URL"
))
c
.
RawRegion
=
common
.
ChooseString
(
c
.
RawRegion
,
os
.
Getenv
(
"SDK_REGION"
),
os
.
Getenv
(
"OS_REGION_NAME"
))
c
.
TenantId
=
common
.
ChooseString
(
c
.
TenantId
,
os
.
Getenv
(
"OS_TENANT_ID"
))
// OpenStack's auto-generated openrc.sh files do not append the suffix
// /tokens to the authentication URL. This ensures it is present when
// specifying the URL.
if
strings
.
Contains
(
c
.
Provider
,
"://"
)
&&
!
strings
.
HasSuffix
(
c
.
Provider
,
"/tokens"
)
{
c
.
Provider
+=
"/tokens"
}
}
authoptions
:=
gophercloud
.
AuthOptions
{
if
c
.
Region
==
""
{
AllowReauth
:
true
,
c
.
Region
=
os
.
Getenv
(
"OS_REGION_NAME"
)
ApiKey
:
c
.
ApiKey
,
TenantId
:
c
.
TenantId
,
TenantName
:
c
.
Project
,
Username
:
c
.
Username
,
Password
:
c
.
Password
,
}
}
default_transport
:=
&
http
.
Transport
{}
// Get as much as possible from the end
ao
,
err
:=
openstack
.
AuthOptionsFromEnv
()
if
c
.
Insecure
{
if
err
!=
nil
{
cfg
:=
new
(
tls
.
Config
)
return
[]
error
{
err
}
cfg
.
InsecureSkipVerify
=
true
default_transport
.
TLSClientConfig
=
cfg
}
}
// For corporate networks it may be the case where we want our API calls
// Override values if we have them in our config
// to be sent through a separate HTTP proxy than external traffic.
overrides
:=
[]
struct
{
if
c
.
ProxyUrl
!=
""
{
From
,
To
*
string
url
,
err
:=
url
.
Parse
(
c
.
ProxyUrl
)
}{
if
err
!=
nil
{
{
&
c
.
Username
,
&
ao
.
Username
},
return
nil
,
err
{
&
c
.
UserID
,
&
ao
.
UserID
},
{
&
c
.
Password
,
&
ao
.
Password
},
{
&
c
.
APIKey
,
&
ao
.
APIKey
},
{
&
c
.
IdentityEndpoint
,
&
ao
.
IdentityEndpoint
},
{
&
c
.
TenantID
,
&
ao
.
TenantID
},
{
&
c
.
TenantName
,
&
ao
.
TenantName
},
{
&
c
.
DomainID
,
&
ao
.
DomainID
},
{
&
c
.
DomainName
,
&
ao
.
DomainName
},
}
for
_
,
s
:=
range
overrides
{
if
*
s
.
From
!=
""
{
*
s
.
To
=
*
s
.
From
}
}
}
// Build the client itself
client
,
err
:=
openstack
.
NewClient
(
ao
.
IdentityEndpoint
)
if
err
!=
nil
{
return
[]
error
{
err
}
}
// The gophercloud.Context has a UseCustomClient method which
// If we have insecure set, then create a custom HTTP client that
// would allow us to override with a new instance of http.Client.
// ignores SSL errors.
default_transport
.
Proxy
=
http
.
ProxyURL
(
url
)
if
c
.
Insecure
{
config
:=
&
tls
.
Config
{
InsecureSkipVerify
:
true
}
transport
:=
&
http
.
Transport
{
TLSClientConfig
:
config
}
client
.
HTTPClient
.
Transport
=
transport
}
}
if
c
.
Insecure
||
c
.
ProxyUrl
!=
""
{
// Auth
http
.
DefaultTransport
=
default_transport
err
=
openstack
.
Authenticate
(
client
,
ao
)
if
err
!=
nil
{
return
[]
error
{
err
}
}
}
return
gophercloud
.
Authenticate
(
c
.
Provider
,
authoptions
)
c
.
osClient
=
client
return
nil
}
}
func
(
c
*
AccessConfig
)
Region
()
string
{
func
(
c
*
AccessConfig
)
computeV2Client
()
(
*
gophercloud
.
ServiceClient
,
error
)
{
return
common
.
ChooseString
(
c
.
RawRegion
,
os
.
Getenv
(
"SDK_REGION"
),
os
.
Getenv
(
"OS_REGION_NAME"
))
return
openstack
.
NewComputeV2
(
c
.
osClient
,
gophercloud
.
EndpointOpts
{
Region
:
c
.
Region
,
Availability
:
c
.
getEndpointType
(),
})
}
}
func
(
c
*
AccessConfig
)
Prepare
(
ctx
*
interpolate
.
Context
)
[]
error
{
func
(
c
*
AccessConfig
)
getEndpointType
()
gophercloud
.
Availability
{
errs
:=
make
([]
error
,
0
)
if
c
.
EndpointType
==
"internal"
||
c
.
EndpointType
==
"internalURL"
{
if
strings
.
HasPrefix
(
c
.
Provider
,
"rackspace"
)
{
return
gophercloud
.
AvailabilityInternal
if
c
.
Region
()
==
""
{
errs
=
append
(
errs
,
fmt
.
Errorf
(
"region must be specified when using rackspace"
))
}
}
}
if
c
.
EndpointType
==
"admin"
||
c
.
EndpointType
==
"adminURL"
{
if
len
(
errs
)
>
0
{
return
gophercloud
.
AvailabilityAdmin
return
errs
}
}
return
gophercloud
.
AvailabilityPublic
return
nil
}
}
builder/openstack/access_config_test.go
deleted
100644 → 0
View file @
46f518f2
package
openstack
import
(
"os"
"testing"
)
func
init
()
{
// Clear out the openstack env vars so they don't
// affect our tests.
os
.
Setenv
(
"SDK_REGION"
,
""
)
os
.
Setenv
(
"OS_REGION_NAME"
,
""
)
}
func
testAccessConfig
()
*
AccessConfig
{
return
&
AccessConfig
{}
}
func
TestAccessConfigPrepare_NoRegion_Rackspace
(
t
*
testing
.
T
)
{
c
:=
testAccessConfig
()
c
.
Provider
=
"rackspace-us"
if
err
:=
c
.
Prepare
(
nil
);
err
==
nil
{
t
.
Fatalf
(
"shouldn't have err: %s"
,
err
)
}
}
func
TestAccessConfigRegionWithEmptyEnv
(
t
*
testing
.
T
)
{
c
:=
testAccessConfig
()
c
.
Prepare
(
nil
)
if
c
.
Region
()
!=
""
{
t
.
Fatalf
(
"Region should be empty"
)
}
}
func
TestAccessConfigRegionWithSdkRegionEnv
(
t
*
testing
.
T
)
{
c
:=
testAccessConfig
()
c
.
Prepare
(
nil
)
expectedRegion
:=
"sdk_region"
os
.
Setenv
(
"SDK_REGION"
,
expectedRegion
)
os
.
Setenv
(
"OS_REGION_NAME"
,
""
)
if
c
.
Region
()
!=
expectedRegion
{
t
.
Fatalf
(
"Region should be: %s"
,
expectedRegion
)
}
}
func
TestAccessConfigRegionWithOsRegionNameEnv
(
t
*
testing
.
T
)
{
c
:=
testAccessConfig
()
c
.
Prepare
(
nil
)
expectedRegion
:=
"os_region_name"
os
.
Setenv
(
"SDK_REGION"
,
""
)
os
.
Setenv
(
"OS_REGION_NAME"
,
expectedRegion
)
if
c
.
Region
()
!=
expectedRegion
{
t
.
Fatalf
(
"Region should be: %s"
,
expectedRegion
)
}
}
func
TestAccessConfigPrepare_NoRegion_PrivateCloud
(
t
*
testing
.
T
)
{
c
:=
testAccessConfig
()
c
.
Provider
=
"http://some-keystone-server:5000/v2.0"
if
err
:=
c
.
Prepare
(
nil
);
err
!=
nil
{
t
.
Fatalf
(
"shouldn't have err: %s"
,
err
)
}
}
func
TestAccessConfigPrepare_Region
(
t
*
testing
.
T
)
{
dfw
:=
"DFW"
c
:=
testAccessConfig
()
c
.
RawRegion
=
dfw
if
err
:=
c
.
Prepare
(
nil
);
err
!=
nil
{
t
.
Fatalf
(
"shouldn't have err: %s"
,
err
)
}
if
dfw
!=
c
.
Region
()
{
t
.
Fatalf
(
"Regions do not match: %s %s"
,
dfw
,
c
.
Region
())
}
}
builder/openstack/artifact.go
View file @
a0d41fcd
...
@@ -4,7 +4,8 @@ import (
...
@@ -4,7 +4,8 @@ import (
"fmt"
"fmt"
"log"
"log"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/images"
)
)
// Artifact is an artifact implementation that contains built images.
// Artifact is an artifact implementation that contains built images.
...
@@ -16,7 +17,7 @@ type Artifact struct {
...
@@ -16,7 +17,7 @@ type Artifact struct {
BuilderIdValue
string
BuilderIdValue
string
// OpenStack connection for performing API stuff.
// OpenStack connection for performing API stuff.
C
onn
gophercloud
.
CloudServersProvider
C
lient
*
gophercloud
.
ServiceClient
}
}
func
(
a
*
Artifact
)
BuilderId
()
string
{
func
(
a
*
Artifact
)
BuilderId
()
string
{
...
@@ -42,5 +43,5 @@ func (a *Artifact) State(name string) interface{} {
...
@@ -42,5 +43,5 @@ func (a *Artifact) State(name string) interface{} {
func
(
a
*
Artifact
)
Destroy
()
error
{
func
(
a
*
Artifact
)
Destroy
()
error
{
log
.
Printf
(
"Destroying image: %s"
,
a
.
ImageId
)
log
.
Printf
(
"Destroying image: %s"
,
a
.
ImageId
)
return
a
.
Conn
.
DeleteImageById
(
a
.
ImageId
)
return
images
.
Delete
(
a
.
Client
,
a
.
ImageId
)
.
ExtractErr
(
)
}
}
builder/openstack/builder.go
View file @
a0d41fcd
...
@@ -9,7 +9,6 @@ import (
...
@@ -9,7 +9,6 @@ import (
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/common"
"log"
"log"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
"github.com/mitchellh/packer/template/interpolate"
...
@@ -55,28 +54,14 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
...
@@ -55,28 +54,14 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}
}
func
(
b
*
Builder
)
Run
(
ui
packer
.
Ui
,
hook
packer
.
Hook
,
cache
packer
.
Cache
)
(
packer
.
Artifact
,
error
)
{
func
(
b
*
Builder
)
Run
(
ui
packer
.
Ui
,
hook
packer
.
Hook
,
cache
packer
.
Cache
)
(
packer
.
Artifact
,
error
)
{
auth
,
err
:=
b
.
config
.
AccessConfig
.
Auth
()
computeClient
,
err
:=
b
.
config
.
computeV2Client
()
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
}
//fetches the api requisites from gophercloud for the appropriate
//openstack variant
api
,
err
:=
gophercloud
.
PopulateApi
(
b
.
config
.
RunConfig
.
OpenstackProvider
)
if
err
!=
nil
{
return
nil
,
err
}
api
.
Region
=
b
.
config
.
AccessConfig
.
Region
()
csp
,
err
:=
gophercloud
.
ServersApi
(
auth
,
api
)
if
err
!=
nil
{
log
.
Printf
(
"Region: %s"
,
b
.
config
.
AccessConfig
.
Region
())
return
nil
,
err
}
}
// Setup the state bag and initial state for the steps
// Setup the state bag and initial state for the steps
state
:=
new
(
multistep
.
BasicStateBag
)
state
:=
new
(
multistep
.
BasicStateBag
)
state
.
Put
(
"config"
,
b
.
config
)
state
.
Put
(
"config"
,
b
.
config
)
state
.
Put
(
"csp"
,
csp
)
state
.
Put
(
"hook"
,
hook
)
state
.
Put
(
"hook"
,
hook
)
state
.
Put
(
"ui"
,
ui
)
state
.
Put
(
"ui"
,
ui
)
...
@@ -101,7 +86,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
...
@@ -101,7 +86,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
FloatingIp
:
b
.
config
.
FloatingIp
,
FloatingIp
:
b
.
config
.
FloatingIp
,
},
},
&
common
.
StepConnectSSH
{
&
common
.
StepConnectSSH
{
SSHAddress
:
SSHAddress
(
c
sp
,
b
.
config
.
SSHInterface
,
b
.
config
.
SSHPort
),
SSHAddress
:
SSHAddress
(
c
omputeClient
,
b
.
config
.
SSHInterface
,
b
.
config
.
SSHPort
),
SSHConfig
:
SSHConfig
(
b
.
config
.
SSHUsername
),
SSHConfig
:
SSHConfig
(
b
.
config
.
SSHUsername
),
SSHWaitTimeout
:
b
.
config
.
SSHTimeout
(),
SSHWaitTimeout
:
b
.
config
.
SSHTimeout
(),
},
},
...
@@ -135,7 +120,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
...
@@ -135,7 +120,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
artifact
:=
&
Artifact
{
artifact
:=
&
Artifact
{
ImageId
:
state
.
Get
(
"image"
)
.
(
string
),
ImageId
:
state
.
Get
(
"image"
)
.
(
string
),
BuilderIdValue
:
BuilderId
,
BuilderIdValue
:
BuilderId
,
C
onn
:
csp
,
C
lient
:
computeClient
,
}
}
return
artifact
,
nil
return
artifact
,
nil
...
...
builder/openstack/server.go
View file @
a0d41fcd
...
@@ -3,12 +3,12 @@ package openstack
...
@@ -3,12 +3,12 @@ package openstack
import
(
import
(
"errors"
"errors"
"fmt"
"fmt"
"github.com/mitchellh/multistep"
"github.com/racker/perigee"
"log"
"log"
"time"
"time"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/mitchellh/multistep"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
)
// StateRefreshFunc is a function type used for StateChangeConf that is
// StateRefreshFunc is a function type used for StateChangeConf that is
...
@@ -33,21 +33,22 @@ type StateChangeConf struct {
...
@@ -33,21 +33,22 @@ type StateChangeConf struct {
// ServerStateRefreshFunc returns a StateRefreshFunc that is used to watch
// ServerStateRefreshFunc returns a StateRefreshFunc that is used to watch
// an openstack server.
// an openstack server.
func
ServerStateRefreshFunc
(
csp
gophercloud
.
CloudServersProvider
,
s
*
gophercloud
.
Server
)
StateRefreshFunc
{
func
ServerStateRefreshFunc
(
client
*
gophercloud
.
ServiceClient
,
s
*
servers
.
Server
)
StateRefreshFunc
{
return
func
()
(
interface
{},
string
,
int
,
error
)
{
return
func
()
(
interface
{},
string
,
int
,
error
)
{
resp
,
err
:=
csp
.
ServerById
(
s
.
Id
)
serverNew
,
err
:=
servers
.
Get
(
client
,
s
.
ID
)
.
Extract
(
)
if
err
!=
nil
{
if
err
!=
nil
{
urce
,
ok
:=
err
.
(
*
perigee
.
UnexpectedResponseCodeError
)
errCode
,
ok
:=
err
.
(
*
gophercloud
.
UnexpectedResponseCodeError
)
if
ok
&&
(
urce
.
Actual
==
404
)
{
if
ok
&&
errCode
.
Actual
==
404
{
log
.
Printf
(
"404 on ServerStateRefresh, returning DELETED"
)
log
.
Printf
(
"[INFO] 404 on ServerStateRefresh, returning DELETED"
)
return
nil
,
"DELETED"
,
0
,
nil
return
nil
,
"DELETED"
,
0
,
nil
}
else
{
}
else
{
log
.
Printf
(
"Error on ServerStateRefresh: %s"
,
err
)
log
.
Printf
(
"
[ERROR]
Error on ServerStateRefresh: %s"
,
err
)
return
nil
,
""
,
0
,
err
return
nil
,
""
,
0
,
err
}
}
}
}
return
resp
,
resp
.
Status
,
resp
.
Progress
,
nil
return
serverNew
,
serverNew
.
Status
,
serverNew
.
Progress
,
nil
}
}
}
}
...
...
builder/openstack/ssh.go
View file @
a0d41fcd
...
@@ -3,49 +3,67 @@ package openstack
...
@@ -3,49 +3,67 @@ package openstack
import
(
import
(
"errors"
"errors"
"fmt"
"fmt"
"github.com/mitchellh/multistep"
"log"
"golang.org/x/crypto/ssh"
"time"
"time"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/mitchellh/multistep"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
"golang.org/x/crypto/ssh"
)
)
// SSHAddress returns a function that can be given to the SSH communicator
// SSHAddress returns a function that can be given to the SSH communicator
// for determining the SSH address based on the server AccessIPv4 setting..
// for determining the SSH address based on the server AccessIPv4 setting..
func
SSHAddress
(
csp
gophercloud
.
CloudServersProvider
,
sshinterface
string
,
port
int
)
func
(
multistep
.
StateBag
)
(
string
,
error
)
{
func
SSHAddress
(
client
*
gophercloud
.
ServiceClient
,
sshinterface
string
,
port
int
)
func
(
multistep
.
StateBag
)
(
string
,
error
)
{
return
func
(
state
multistep
.
StateBag
)
(
string
,
error
)
{
return
func
(
state
multistep
.
StateBag
)
(
string
,
error
)
{
s
:=
state
.
Get
(
"server"
)
.
(
*
gophercloud
.
Server
)
s
:=
state
.
Get
(
"server"
)
.
(
*
servers
.
Server
)
if
ip
:=
state
.
Get
(
"access_ip"
)
.
(
gophercloud
.
FloatingIp
);
ip
.
Ip
!=
""
{
// If we have a floating IP, use that
return
fmt
.
Sprintf
(
"%s:%d"
,
ip
.
Ip
,
port
),
nil
ip
:=
state
.
Get
(
"access_ip"
)
.
(
*
floatingip
.
FloatingIP
)
if
ip
!=
nil
&&
ip
.
FixedIP
!=
""
{
return
fmt
.
Sprintf
(
"%s:%d"
,
ip
.
FixedIP
,
port
),
nil
}
}
ip_pools
,
err
:=
s
.
AllAddressPools
()
if
s
.
AccessIPv4
!=
""
{
if
err
!=
nil
{
return
fmt
.
Sprintf
(
"%s:%d"
,
s
.
AccessIPv4
,
port
),
nil
return
""
,
errors
.
New
(
"Error parsing SSH addresses"
)
}
}
for
pool
,
addresses
:=
range
ip_pools
{
if
sshinterface
!=
""
{
// Get all the addresses associated with this server. This
if
pool
!=
sshinterface
{
// was taken directly from Terraform.
continue
for
_
,
networkAddresses
:=
range
s
.
Addresses
{
}
elements
,
ok
:=
networkAddresses
.
([]
interface
{})
if
!
ok
{
log
.
Printf
(
"[ERROR] Unknown return type for address field: %#v"
,
networkAddresses
)
continue
}
}
if
pool
!=
""
{
for
_
,
address
:=
range
addresses
{
for
_
,
element
:=
range
elements
{
if
address
.
Addr
!=
""
&&
address
.
Version
==
4
{
var
addr
string
return
fmt
.
Sprintf
(
"%s:%d"
,
address
.
Addr
,
port
),
nil
address
:=
element
.
(
map
[
string
]
interface
{})
if
address
[
"OS-EXT-IPS:type"
]
==
"floating"
{
addr
=
address
[
"addr"
]
.
(
string
)
}
else
{
if
address
[
"version"
]
.
(
float64
)
==
4
{
addr
=
address
[
"addr"
]
.
(
string
)
}
}
}
}
if
addr
!=
""
{
return
fmt
.
Sprintf
(
"%s:%d"
,
addr
,
port
),
nil
}
}
}
}
}
serverState
,
err
:=
csp
.
ServerById
(
s
.
Id
)
s
,
err
:=
servers
.
Get
(
client
,
s
.
ID
)
.
Extract
()
if
err
!=
nil
{
if
err
!=
nil
{
return
""
,
err
return
""
,
err
}
}
state
.
Put
(
"server"
,
s
erverState
)
state
.
Put
(
"server"
,
s
)
time
.
Sleep
(
1
*
time
.
Second
)
time
.
Sleep
(
1
*
time
.
Second
)
return
""
,
errors
.
New
(
"couldn't determine IP address for server"
)
return
""
,
errors
.
New
(
"couldn't determine IP address for server"
)
...
...
builder/openstack/step_allocate_ip.go
View file @
a0d41fcd
...
@@ -2,10 +2,11 @@ package openstack
...
@@ -2,10 +2,11 @@ package openstack
import
(
import
(
"fmt"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
"github.com/
mitchellh/gophercloud-fork-40444fb
"
"github.com/
rackspace/gophercloud/openstack/compute/v2/servers
"
)
)
type
StepAllocateIp
struct
{
type
StepAllocateIp
struct
{
...
@@ -15,53 +16,78 @@ type StepAllocateIp struct {
...
@@ -15,53 +16,78 @@ type StepAllocateIp struct {
func
(
s
*
StepAllocateIp
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
func
(
s
*
StepAllocateIp
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
csp
:=
state
.
Get
(
"csp"
)
.
(
gophercloud
.
CloudServersProvider
)
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
server
:=
state
.
Get
(
"server"
)
.
(
*
gophercloud
.
Server
)
server
:=
state
.
Get
(
"server"
)
.
(
*
servers
.
Server
)
// We need the v2 compute client
client
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
var
instanceIp
gophercloud
.
FloatingIp
var
instanceIp
*
floatingip
.
FloatingIP
// This is here in case we error out before putting instanceIp into the
// This is here in case we error out before putting instanceIp into the
// statebag below, because it is requested by Cleanup()
// statebag below, because it is requested by Cleanup()
state
.
Put
(
"access_ip"
,
instanceIp
)
state
.
Put
(
"access_ip"
,
instanceIp
)
if
s
.
FloatingIp
!=
""
{
if
s
.
FloatingIp
!=
""
{
instanceIp
.
Ip
=
s
.
FloatingIp
*
instanceIp
=
floatingip
.
FloatingIP
{
FixedIP
:
s
.
FloatingIp
}
}
else
if
s
.
FloatingIpPool
!=
""
{
}
else
if
s
.
FloatingIpPool
!=
""
{
newIp
,
err
:=
csp
.
CreateFloatingIp
(
s
.
FloatingIpPool
)
newIp
,
err
:=
floatingip
.
Create
(
client
,
floatingip
.
CreateOpts
{
Pool
:
s
.
FloatingIpPool
,
})
.
Extract
()
if
err
!=
nil
{
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error creating floating ip from pool '%s'"
,
s
.
FloatingIpPool
)
err
:=
fmt
.
Errorf
(
"Error creating floating ip from pool '%s'"
,
s
.
FloatingIpPool
)
state
.
Put
(
"error"
,
err
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
return
multistep
.
ActionHalt
}
}
instanceIp
=
newIp
ui
.
Say
(
fmt
.
Sprintf
(
"Created temporary floating IP %s..."
,
instanceIp
.
Ip
))
*
instanceIp
=
*
newIp
ui
.
Say
(
fmt
.
Sprintf
(
"Created temporary floating IP %s..."
,
instanceIp
.
FixedIP
))
}
}
if
instanceIp
.
Ip
!=
""
{
if
instanceIp
!=
nil
&&
instanceIp
.
FixedIP
!=
""
{
if
err
:=
csp
.
AssociateFloatingIp
(
server
.
Id
,
instanceIp
);
err
!=
nil
{
err
:=
floatingip
.
Associate
(
client
,
server
.
ID
,
instanceIp
.
FixedIP
)
.
ExtractErr
()
err
:=
fmt
.
Errorf
(
"Error associating floating IP %s with instance."
,
instanceIp
.
Ip
)
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error associating floating IP %s with instance."
,
instanceIp
.
FixedIP
)
state
.
Put
(
"error"
,
err
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
return
multistep
.
ActionHalt
}
else
{
ui
.
Say
(
fmt
.
Sprintf
(
"Added floating IP %s to instance..."
,
instanceIp
.
Ip
))
}
}
ui
.
Say
(
fmt
.
Sprintf
(
"Added floating IP %s to instance..."
,
instanceIp
.
FixedIP
))
}
}
state
.
Put
(
"access_ip"
,
instanceIp
)
state
.
Put
(
"access_ip"
,
instanceIp
)
return
multistep
.
ActionContinue
return
multistep
.
ActionContinue
}
}
func
(
s
*
StepAllocateIp
)
Cleanup
(
state
multistep
.
StateBag
)
{
func
(
s
*
StepAllocateIp
)
Cleanup
(
state
multistep
.
StateBag
)
{
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
csp
:=
state
.
Get
(
"csp"
)
.
(
gophercloud
.
CloudServersProvider
)
instanceIp
:=
state
.
Get
(
"access_ip"
)
.
(
*
floatingip
.
FloatingIP
)
instanceIp
:=
state
.
Get
(
"access_ip"
)
.
(
gophercloud
.
FloatingIp
)
if
s
.
FloatingIpPool
!=
""
&&
instanceIp
.
Id
!=
0
{
// We need the v2 compute client
if
err
:=
csp
.
DeleteFloatingIp
(
instanceIp
);
err
!=
nil
{
client
,
err
:=
config
.
computeV2Client
()
ui
.
Error
(
fmt
.
Sprintf
(
"Error deleting temporary floating IP %s"
,
instanceIp
.
Ip
))
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error deleting temporary floating IP %s"
,
instanceIp
.
FixedIP
))
return
}
if
s
.
FloatingIpPool
!=
""
&&
instanceIp
.
ID
!=
""
{
if
err
:=
floatingip
.
Delete
(
client
,
instanceIp
.
ID
)
.
ExtractErr
();
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error deleting temporary floating IP %s"
,
instanceIp
.
FixedIP
))
return
return
}
}
ui
.
Say
(
fmt
.
Sprintf
(
"Deleted temporary floating IP %s"
,
instanceIp
.
Ip
))
ui
.
Say
(
fmt
.
Sprintf
(
"Deleted temporary floating IP %s"
,
instanceIp
.
FixedIP
))
}
}
}
}
builder/openstack/step_create_image.go
View file @
a0d41fcd
...
@@ -2,28 +2,36 @@ package openstack
...
@@ -2,28 +2,36 @@ package openstack
import
(
import
(
"fmt"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"log"
"time"
"time"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/images"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
)
type
stepCreateImage
struct
{}
type
stepCreateImage
struct
{}
func
(
s
*
stepCreateImage
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
func
(
s
*
stepCreateImage
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
csp
:=
state
.
Get
(
"csp"
)
.
(
gophercloud
.
CloudServersProvider
)
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
server
:=
state
.
Get
(
"server"
)
.
(
*
gophercloud
.
Server
)
server
:=
state
.
Get
(
"server"
)
.
(
*
servers
.
Server
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
client
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
// Create the image
// Create the image
ui
.
Say
(
fmt
.
Sprintf
(
"Creating the image: %s"
,
config
.
ImageName
))
ui
.
Say
(
fmt
.
Sprintf
(
"Creating the image: %s"
,
config
.
ImageName
))
createOpts
:=
gophercloud
.
CreateImage
{
imageId
,
err
:=
servers
.
CreateImage
(
client
,
server
.
ID
,
servers
.
CreateImageOpts
{
Name
:
config
.
ImageName
,
Name
:
config
.
ImageName
,
}
})
.
ExtractImageID
()
imageId
,
err
:=
csp
.
CreateImage
(
server
.
Id
,
createOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error creating image: %s"
,
err
)
err
:=
fmt
.
Errorf
(
"Error creating image: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
state
.
Put
(
"error"
,
err
)
...
@@ -32,12 +40,12 @@ func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction {
...
@@ -32,12 +40,12 @@ func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction {
}
}
// Set the Image ID in the state
// Set the Image ID in the state
ui
.
Say
(
fmt
.
Sprintf
(
"Image: %s"
,
imageId
))
ui
.
Message
(
fmt
.
Sprintf
(
"Image: %s"
,
imageId
))
state
.
Put
(
"image"
,
imageId
)
state
.
Put
(
"image"
,
imageId
)
// Wait for the image to become ready
// Wait for the image to become ready
ui
.
Say
(
"Waiting for image to become ready..."
)
ui
.
Say
(
"Waiting for image to become ready..."
)
if
err
:=
WaitForImage
(
c
sp
,
imageId
);
err
!=
nil
{
if
err
:=
WaitForImage
(
c
lient
,
imageId
);
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error waiting for image: %s"
,
err
)
err
:=
fmt
.
Errorf
(
"Error waiting for image: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
ui
.
Error
(
err
.
Error
())
...
@@ -52,10 +60,17 @@ func (s *stepCreateImage) Cleanup(multistep.StateBag) {
...
@@ -52,10 +60,17 @@ func (s *stepCreateImage) Cleanup(multistep.StateBag) {
}
}
// WaitForImage waits for the given Image ID to become ready.
// WaitForImage waits for the given Image ID to become ready.
func
WaitForImage
(
c
sp
gophercloud
.
CloudServersProvider
,
imageId
string
)
error
{
func
WaitForImage
(
c
lient
*
gophercloud
.
ServiceClient
,
imageId
string
)
error
{
for
{
for
{
image
,
err
:=
csp
.
ImageById
(
imageId
)
image
,
err
:=
images
.
Get
(
client
,
imageId
)
.
Extract
(
)
if
err
!=
nil
{
if
err
!=
nil
{
errCode
,
ok
:=
err
.
(
*
gophercloud
.
UnexpectedResponseCodeError
)
if
ok
&&
errCode
.
Actual
==
500
{
log
.
Printf
(
"[ERROR] 500 error received, will ignore and retry: %s"
,
err
)
time
.
Sleep
(
2
*
time
.
Second
)
continue
}
return
err
return
err
}
}
...
...
builder/openstack/step_key_pair.go
View file @
a0d41fcd
...
@@ -2,14 +2,13 @@ package openstack
...
@@ -2,14 +2,13 @@ package openstack
import
(
import
(
"fmt"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common/uuid"
"github.com/mitchellh/packer/packer"
"log"
"os"
"os"
"runtime"
"runtime"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common/uuid"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
)
)
type
StepKeyPair
struct
{
type
StepKeyPair
struct
{
...
@@ -19,18 +18,28 @@ type StepKeyPair struct {
...
@@ -19,18 +18,28 @@ type StepKeyPair struct {
}
}
func
(
s
*
StepKeyPair
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
func
(
s
*
StepKeyPair
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
c
sp
:=
state
.
Get
(
"csp"
)
.
(
gophercloud
.
CloudServersProvider
)
c
onfig
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
ui
.
Say
(
"Creating temporary keypair for this instance..."
)
ui
.
Say
(
"Creating temporary keypair for this instance..."
)
keyName
:=
fmt
.
Sprintf
(
"packer %s"
,
uuid
.
TimeOrderedUUID
())
keyName
:=
fmt
.
Sprintf
(
"packer %s"
,
uuid
.
TimeOrderedUUID
())
log
.
Printf
(
"temporary keypair name: %s"
,
keyName
)
keypair
,
err
:=
keypairs
.
Create
(
computeClient
,
keypairs
.
CreateOpts
{
keyResp
,
err
:=
csp
.
CreateKeyPair
(
gophercloud
.
NewKeyPair
{
Name
:
keyName
})
Name
:
keyName
,
})
.
Extract
()
if
err
!=
nil
{
if
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error creating temporary keypair: %s"
,
err
))
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error creating temporary keypair: %s"
,
err
))
return
multistep
.
ActionHalt
return
multistep
.
ActionHalt
}
}
if
keyResp
.
PrivateKey
==
""
{
if
keypair
.
PrivateKey
==
""
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"The temporary keypair returned was blank"
))
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"The temporary keypair returned was blank"
))
return
multistep
.
ActionHalt
return
multistep
.
ActionHalt
}
}
...
@@ -47,7 +56,7 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
...
@@ -47,7 +56,7 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
defer
f
.
Close
()
defer
f
.
Close
()
// Write the key out
// Write the key out
if
_
,
err
:=
f
.
Write
([]
byte
(
key
Resp
.
PrivateKey
));
err
!=
nil
{
if
_
,
err
:=
f
.
Write
([]
byte
(
key
pair
.
PrivateKey
));
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error saving debug key: %s"
,
err
))
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error saving debug key: %s"
,
err
))
return
multistep
.
ActionHalt
return
multistep
.
ActionHalt
}
}
...
@@ -66,7 +75,7 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
...
@@ -66,7 +75,7 @@ func (s *StepKeyPair) Run(state multistep.StateBag) multistep.StepAction {
// Set some state data for use in future steps
// Set some state data for use in future steps
state
.
Put
(
"keyPair"
,
keyName
)
state
.
Put
(
"keyPair"
,
keyName
)
state
.
Put
(
"privateKey"
,
key
Resp
.
PrivateKey
)
state
.
Put
(
"privateKey"
,
key
pair
.
PrivateKey
)
return
multistep
.
ActionContinue
return
multistep
.
ActionContinue
}
}
...
@@ -77,11 +86,19 @@ func (s *StepKeyPair) Cleanup(state multistep.StateBag) {
...
@@ -77,11 +86,19 @@ func (s *StepKeyPair) Cleanup(state multistep.StateBag) {
return
return
}
}
c
sp
:=
state
.
Get
(
"csp"
)
.
(
gophercloud
.
CloudServersProvider
)
c
onfig
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error cleaning up keypair. Please delete the key manually: %s"
,
s
.
keyName
))
return
}
ui
.
Say
(
"Deleting temporary keypair..."
)
ui
.
Say
(
"Deleting temporary keypair..."
)
err
:=
csp
.
DeleteKeyPair
(
s
.
keyName
)
err
=
keypairs
.
Delete
(
computeClient
,
s
.
keyName
)
.
ExtractErr
(
)
if
err
!=
nil
{
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
ui
.
Error
(
fmt
.
Sprintf
(
"Error cleaning up keypair. Please delete the key manually: %s"
,
s
.
keyName
))
"Error cleaning up keypair. Please delete the key manually: %s"
,
s
.
keyName
))
...
...
builder/openstack/step_run_source_server.go
View file @
a0d41fcd
...
@@ -2,11 +2,12 @@ package openstack
...
@@ -2,11 +2,12 @@ package openstack
import
(
import
(
"fmt"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"log"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
)
type
StepRunSourceServer
struct
{
type
StepRunSourceServer
struct
{
...
@@ -16,37 +17,38 @@ type StepRunSourceServer struct {
...
@@ -16,37 +17,38 @@ type StepRunSourceServer struct {
SecurityGroups
[]
string
SecurityGroups
[]
string
Networks
[]
string
Networks
[]
string
server
*
gophercloud
.
Server
server
*
servers
.
Server
}
}
func
(
s
*
StepRunSourceServer
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
func
(
s
*
StepRunSourceServer
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
c
sp
:=
state
.
Get
(
"csp"
)
.
(
gophercloud
.
CloudServersProvider
)
c
onfig
:=
state
.
Get
(
"config"
)
.
(
Config
)
keyName
:=
state
.
Get
(
"keyPair"
)
.
(
string
)
keyName
:=
state
.
Get
(
"keyPair"
)
.
(
string
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
//
XXX - validate image and flavor is available
//
We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
securityGroups
:=
make
([]
map
[
string
]
interface
{},
len
(
s
.
SecurityGroups
))
if
err
!=
nil
{
for
i
,
groupName
:=
range
s
.
SecurityGroups
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
s
ecurityGroups
[
i
]
=
make
(
map
[
string
]
interface
{}
)
s
tate
.
Put
(
"error"
,
err
)
securityGroups
[
i
][
"name"
]
=
groupName
return
multistep
.
ActionHalt
}
}
networks
:=
make
([]
gophercloud
.
NetworkConfig
,
len
(
s
.
Networks
))
networks
:=
make
([]
servers
.
Network
,
len
(
s
.
Networks
))
for
i
,
networkUuid
:=
range
s
.
Networks
{
for
i
,
networkUuid
:=
range
s
.
Networks
{
networks
[
i
]
.
U
uid
=
networkUuid
networks
[
i
]
.
U
UID
=
networkUuid
}
}
server
:=
gophercloud
.
NewServer
{
s
.
server
,
err
=
servers
.
Create
(
computeClient
,
keypairs
.
CreateOptsExt
{
Name
:
s
.
Name
,
CreateOptsBuilder
:
servers
.
CreateOpts
{
ImageRef
:
s
.
SourceImage
,
Name
:
s
.
Name
,
FlavorRef
:
s
.
Flavor
,
ImageRef
:
s
.
SourceImage
,
KeyPairName
:
keyName
,
FlavorName
:
s
.
Flavor
,
SecurityGroup
:
securityGroups
,
SecurityGroups
:
s
.
SecurityGroups
,
Networks
:
networks
,
Networks
:
networks
,
}
},
serverResp
,
err
:=
csp
.
CreateServer
(
server
)
KeyName
:
keyName
,
})
.
Extract
()
if
err
!=
nil
{
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error launching source server: %s"
,
err
)
err
:=
fmt
.
Errorf
(
"Error launching source server: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
state
.
Put
(
"error"
,
err
)
...
@@ -54,25 +56,24 @@ func (s *StepRunSourceServer) Run(state multistep.StateBag) multistep.StepAction
...
@@ -54,25 +56,24 @@ func (s *StepRunSourceServer) Run(state multistep.StateBag) multistep.StepAction
return
multistep
.
ActionHalt
return
multistep
.
ActionHalt
}
}
s
.
server
,
err
=
csp
.
ServerById
(
serverResp
.
Id
)
log
.
Printf
(
"server id: %s"
,
s
.
server
.
ID
)
log
.
Printf
(
"server id: %s"
,
s
.
server
.
Id
)
ui
.
Say
(
fmt
.
Sprintf
(
"Waiting for server (%s) to become ready..."
,
s
.
server
.
I
d
))
ui
.
Say
(
fmt
.
Sprintf
(
"Waiting for server (%s) to become ready..."
,
s
.
server
.
I
D
))
stateChange
:=
StateChangeConf
{
stateChange
:=
StateChangeConf
{
Pending
:
[]
string
{
"BUILD"
},
Pending
:
[]
string
{
"BUILD"
},
Target
:
"ACTIVE"
,
Target
:
"ACTIVE"
,
Refresh
:
ServerStateRefreshFunc
(
c
sp
,
s
.
server
),
Refresh
:
ServerStateRefreshFunc
(
c
omputeClient
,
s
.
server
),
StepState
:
state
,
StepState
:
state
,
}
}
latestServer
,
err
:=
WaitForState
(
&
stateChange
)
latestServer
,
err
:=
WaitForState
(
&
stateChange
)
if
err
!=
nil
{
if
err
!=
nil
{
err
:=
fmt
.
Errorf
(
"Error waiting for server (%s) to become ready: %s"
,
s
.
server
.
I
d
,
err
)
err
:=
fmt
.
Errorf
(
"Error waiting for server (%s) to become ready: %s"
,
s
.
server
.
I
D
,
err
)
state
.
Put
(
"error"
,
err
)
state
.
Put
(
"error"
,
err
)
ui
.
Error
(
err
.
Error
())
ui
.
Error
(
err
.
Error
())
return
multistep
.
ActionHalt
return
multistep
.
ActionHalt
}
}
s
.
server
=
latestServer
.
(
*
gophercloud
.
Server
)
s
.
server
=
latestServer
.
(
*
servers
.
Server
)
state
.
Put
(
"server"
,
s
.
server
)
state
.
Put
(
"server"
,
s
.
server
)
return
multistep
.
ActionContinue
return
multistep
.
ActionContinue
...
@@ -83,18 +84,25 @@ func (s *StepRunSourceServer) Cleanup(state multistep.StateBag) {
...
@@ -83,18 +84,25 @@ func (s *StepRunSourceServer) Cleanup(state multistep.StateBag) {
return
return
}
}
c
sp
:=
state
.
Get
(
"csp"
)
.
(
gophercloud
.
CloudServersProvider
)
c
onfig
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error terminating server, may still be around: %s"
,
err
))
return
}
ui
.
Say
(
"Terminating the source server..."
)
ui
.
Say
(
"Terminating the source server..."
)
if
err
:=
csp
.
DeleteServerById
(
s
.
server
.
Id
);
err
!=
nil
{
if
err
:=
servers
.
Delete
(
computeClient
,
s
.
server
.
ID
)
.
ExtractErr
(
);
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error terminating server, may still be around: %s"
,
err
))
ui
.
Error
(
fmt
.
Sprintf
(
"Error terminating server, may still be around: %s"
,
err
))
return
return
}
}
stateChange
:=
StateChangeConf
{
stateChange
:=
StateChangeConf
{
Pending
:
[]
string
{
"ACTIVE"
,
"BUILD"
,
"REBUILD"
,
"SUSPENDED"
},
Pending
:
[]
string
{
"ACTIVE"
,
"BUILD"
,
"REBUILD"
,
"SUSPENDED"
},
Refresh
:
ServerStateRefreshFunc
(
c
sp
,
s
.
server
),
Refresh
:
ServerStateRefreshFunc
(
c
omputeClient
,
s
.
server
),
Target
:
"DELETED"
,
Target
:
"DELETED"
,
}
}
...
...
builder/openstack/step_wait_for_rackconnect.go
View file @
a0d41fcd
...
@@ -2,11 +2,11 @@ package openstack
...
@@ -2,11 +2,11 @@ package openstack
import
(
import
(
"fmt"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"time"
"time"
"github.com/mitchellh/gophercloud-fork-40444fb"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
)
type
StepWaitForRackConnect
struct
{
type
StepWaitForRackConnect
struct
{
...
@@ -18,14 +18,22 @@ func (s *StepWaitForRackConnect) Run(state multistep.StateBag) multistep.StepAct
...
@@ -18,14 +18,22 @@ func (s *StepWaitForRackConnect) Run(state multistep.StateBag) multistep.StepAct
return
multistep
.
ActionContinue
return
multistep
.
ActionContinue
}
}
c
sp
:=
state
.
Get
(
"csp"
)
.
(
gophercloud
.
CloudServersProvider
)
c
onfig
:=
state
.
Get
(
"config"
)
.
(
Config
)
server
:=
state
.
Get
(
"server"
)
.
(
*
gophercloud
.
Server
)
server
:=
state
.
Get
(
"server"
)
.
(
*
servers
.
Server
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
ui
.
Say
(
fmt
.
Sprintf
(
"Waiting for server (%s) to become RackConnect ready..."
,
server
.
Id
))
// We need the v2 compute client
computeClient
,
err
:=
config
.
computeV2Client
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error initializing compute client: %s"
,
err
)
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
ui
.
Say
(
fmt
.
Sprintf
(
"Waiting for server (%s) to become RackConnect ready..."
,
server
.
ID
))
for
{
for
{
server
,
err
:=
csp
.
ServerById
(
server
.
Id
)
server
,
err
=
servers
.
Get
(
computeClient
,
server
.
ID
)
.
Extract
(
)
if
err
!=
nil
{
if
err
!=
nil
{
return
multistep
.
ActionHalt
return
multistep
.
ActionHalt
}
}
...
...
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