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
3bdd9ccb
Commit
3bdd9ccb
authored
Jul 10, 2014
by
Mitchell Hashimoto
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1289 from mitchellh/vagrant-cloud-post-processor
Vagrant Cloud Post-Processor
parents
cbfb6ec3
e528cd7c
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1091 additions
and
2 deletions
+1091
-2
config.go
config.go
+2
-1
plugin/post-processor-vagrant-cloud/main.go
plugin/post-processor-vagrant-cloud/main.go
+15
-0
plugin/post-processor-vagrant-cloud/main_test.go
plugin/post-processor-vagrant-cloud/main_test.go
+1
-0
post-processor/vagrant-cloud/artifact.go
post-processor/vagrant-cloud/artifact.go
+39
-0
post-processor/vagrant-cloud/artifact_test.go
post-processor/vagrant-cloud/artifact_test.go
+14
-0
post-processor/vagrant-cloud/client.go
post-processor/vagrant-cloud/client.go
+185
-0
post-processor/vagrant-cloud/post-processor.go
post-processor/vagrant-cloud/post-processor.go
+171
-0
post-processor/vagrant-cloud/post-processor_test.go
post-processor/vagrant-cloud/post-processor_test.go
+59
-0
post-processor/vagrant-cloud/step_create_provider.go
post-processor/vagrant-cloud/step_create_provider.go
+91
-0
post-processor/vagrant-cloud/step_create_version.go
post-processor/vagrant-cloud/step_create_version.go
+97
-0
post-processor/vagrant-cloud/step_prepare_upload.go
post-processor/vagrant-cloud/step_prepare_upload.go
+54
-0
post-processor/vagrant-cloud/step_release_version.go
post-processor/vagrant-cloud/step_release_version.go
+44
-0
post-processor/vagrant-cloud/step_upload.go
post-processor/vagrant-cloud/step_upload.go
+37
-0
post-processor/vagrant-cloud/step_verify_box.go
post-processor/vagrant-cloud/step_verify_box.go
+66
-0
post-processor/vagrant-cloud/step_verify_upload.go
post-processor/vagrant-cloud/step_verify_upload.go
+103
-0
post-processor/vagrant/artifact.go
post-processor/vagrant/artifact.go
+1
-1
post-processor/vagrant/artifact_test.go
post-processor/vagrant/artifact_test.go
+7
-0
website/source/docs/post-processors/vagrant-cloud.html.markdown
...e/source/docs/post-processors/vagrant-cloud.html.markdown
+104
-0
website/source/layouts/docs.erb
website/source/layouts/docs.erb
+1
-0
No files found.
config.go
View file @
3bdd9ccb
...
...
@@ -47,7 +47,8 @@ const defaultConfig = `
"vagrant": "packer-post-processor-vagrant",
"vsphere": "packer-post-processor-vsphere",
"docker-push": "packer-post-processor-docker-push",
"docker-import": "packer-post-processor-docker-import"
"docker-import": "packer-post-processor-docker-import",
"vagrant-cloud": "packer-post-processor-vagrant-cloud"
},
"provisioners": {
...
...
plugin/post-processor-vagrant-cloud/main.go
0 → 100644
View file @
3bdd9ccb
package
main
import
(
"github.com/mitchellh/packer/packer/plugin"
"github.com/mitchellh/packer/post-processor/vagrant-cloud"
)
func
main
()
{
server
,
err
:=
plugin
.
Server
()
if
err
!=
nil
{
panic
(
err
)
}
server
.
RegisterPostProcessor
(
new
(
vagrantcloud
.
PostProcessor
))
server
.
Serve
()
}
plugin/post-processor-vagrant-cloud/main_test.go
0 → 100644
View file @
3bdd9ccb
package
main
post-processor/vagrant-cloud/artifact.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"fmt"
)
const
BuilderId
=
"pearkes.post-processor.vagrant-cloud"
type
Artifact
struct
{
Tag
string
Provider
string
}
func
NewArtifact
(
provider
,
tag
string
)
*
Artifact
{
return
&
Artifact
{
Tag
:
tag
,
Provider
:
provider
,
}
}
func
(
*
Artifact
)
BuilderId
()
string
{
return
BuilderId
}
func
(
a
*
Artifact
)
Files
()
[]
string
{
return
nil
}
func
(
a
*
Artifact
)
Id
()
string
{
return
""
}
func
(
a
*
Artifact
)
String
()
string
{
return
fmt
.
Sprintf
(
"'%s': %s"
,
a
.
Provider
,
a
.
Tag
)
}
func
(
a
*
Artifact
)
Destroy
()
error
{
return
nil
}
post-processor/vagrant-cloud/artifact_test.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"github.com/mitchellh/packer/packer"
"testing"
)
func
TestArtifact_ImplementsArtifact
(
t
*
testing
.
T
)
{
var
raw
interface
{}
raw
=
&
Artifact
{}
if
_
,
ok
:=
raw
.
(
packer
.
Artifact
);
!
ok
{
t
.
Fatalf
(
"Artifact should be a Artifact"
)
}
}
post-processor/vagrant-cloud/client.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"mime/multipart"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
)
type
VagrantCloudClient
struct
{
// The http client for communicating
client
*
http
.
Client
// The base URL of the API
BaseURL
string
// Access token
AccessToken
string
}
type
VagrantCloudErrors
struct
{
Errors
map
[
string
][]
string
`json:"errors"`
}
func
(
v
VagrantCloudErrors
)
FormatErrors
()
string
{
errs
:=
make
([]
string
,
0
)
for
e
:=
range
v
.
Errors
{
msg
:=
fmt
.
Sprintf
(
"%s %s"
,
e
,
strings
.
Join
(
v
.
Errors
[
e
],
","
))
errs
=
append
(
errs
,
msg
)
}
return
strings
.
Join
(
errs
,
". "
)
}
func
(
v
VagrantCloudClient
)
New
(
baseUrl
string
,
token
string
)
*
VagrantCloudClient
{
c
:=
&
VagrantCloudClient
{
client
:
&
http
.
Client
{
Transport
:
&
http
.
Transport
{
Proxy
:
http
.
ProxyFromEnvironment
,
},
},
BaseURL
:
baseUrl
,
AccessToken
:
token
,
}
return
c
}
func
decodeBody
(
resp
*
http
.
Response
,
out
interface
{})
error
{
defer
resp
.
Body
.
Close
()
dec
:=
json
.
NewDecoder
(
resp
.
Body
)
return
dec
.
Decode
(
out
)
}
// encodeBody is used to encode a request body
func
encodeBody
(
obj
interface
{})
(
io
.
Reader
,
error
)
{
buf
:=
bytes
.
NewBuffer
(
nil
)
enc
:=
json
.
NewEncoder
(
buf
)
if
err
:=
enc
.
Encode
(
obj
);
err
!=
nil
{
return
nil
,
err
}
return
buf
,
nil
}
func
(
v
VagrantCloudClient
)
Get
(
path
string
)
(
*
http
.
Response
,
error
)
{
params
:=
url
.
Values
{}
params
.
Set
(
"access_token"
,
v
.
AccessToken
)
reqUrl
:=
fmt
.
Sprintf
(
"%s/%s?%s"
,
v
.
BaseURL
,
path
,
params
.
Encode
())
// Scrub API key for logs
scrubbedUrl
:=
strings
.
Replace
(
reqUrl
,
v
.
AccessToken
,
"ACCESS_TOKEN"
,
-
1
)
log
.
Printf
(
"Post-Processor Vagrant Cloud API GET: %s"
,
scrubbedUrl
)
req
,
err
:=
http
.
NewRequest
(
"GET"
,
reqUrl
,
nil
)
req
.
Header
.
Add
(
"Content-Type"
,
"application/json"
)
resp
,
err
:=
v
.
client
.
Do
(
req
)
log
.
Printf
(
"Post-Processor Vagrant Cloud API Response:
\n\n
%s"
,
resp
)
return
resp
,
err
}
func
(
v
VagrantCloudClient
)
Delete
(
path
string
)
(
*
http
.
Response
,
error
)
{
params
:=
url
.
Values
{}
params
.
Set
(
"access_token"
,
v
.
AccessToken
)
reqUrl
:=
fmt
.
Sprintf
(
"%s/%s?%s"
,
v
.
BaseURL
,
path
,
params
.
Encode
())
// Scrub API key for logs
scrubbedUrl
:=
strings
.
Replace
(
reqUrl
,
v
.
AccessToken
,
"ACCESS_TOKEN"
,
-
1
)
log
.
Printf
(
"Post-Processor Vagrant Cloud API DELETE: %s"
,
scrubbedUrl
)
req
,
err
:=
http
.
NewRequest
(
"DELETE"
,
reqUrl
,
nil
)
req
.
Header
.
Add
(
"Content-Type"
,
"application/json"
)
resp
,
err
:=
v
.
client
.
Do
(
req
)
log
.
Printf
(
"Post-Processor Vagrant Cloud API Response:
\n\n
%s"
,
resp
)
return
resp
,
err
}
func
(
v
VagrantCloudClient
)
Upload
(
path
string
,
url
string
)
(
*
http
.
Response
,
error
)
{
file
,
err
:=
os
.
Open
(
path
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Error opening file for upload: %s"
,
err
)
}
defer
file
.
Close
()
body
:=
&
bytes
.
Buffer
{}
writer
:=
multipart
.
NewWriter
(
body
)
part
,
err
:=
writer
.
CreateFormFile
(
"file"
,
filepath
.
Base
(
path
))
if
err
!=
nil
{
return
nil
,
err
}
_
,
err
=
io
.
Copy
(
part
,
file
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Error uploading file: %s"
,
err
)
}
request
,
err
:=
http
.
NewRequest
(
"PUT"
,
url
,
body
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Error preparing upload request: %s"
,
err
)
}
log
.
Printf
(
"Post-Processor Vagrant Cloud API Upload: %s %s"
,
path
,
url
)
resp
,
err
:=
v
.
client
.
Do
(
request
)
log
.
Printf
(
"Post-Processor Vagrant Cloud Upload Response:
\n\n
%s"
,
resp
)
return
resp
,
err
}
func
(
v
VagrantCloudClient
)
Post
(
path
string
,
body
interface
{})
(
*
http
.
Response
,
error
)
{
params
:=
url
.
Values
{}
params
.
Set
(
"access_token"
,
v
.
AccessToken
)
reqUrl
:=
fmt
.
Sprintf
(
"%s/%s?%s"
,
v
.
BaseURL
,
path
,
params
.
Encode
())
encBody
,
err
:=
encodeBody
(
body
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Error encoding body for request: %s"
,
err
)
}
// Scrub API key for logs
scrubbedUrl
:=
strings
.
Replace
(
reqUrl
,
v
.
AccessToken
,
"ACCESS_TOKEN"
,
-
1
)
log
.
Printf
(
"Post-Processor Vagrant Cloud API POST: %s.
\n\n
Body: %s"
,
scrubbedUrl
,
encBody
)
req
,
err
:=
http
.
NewRequest
(
"POST"
,
reqUrl
,
encBody
)
req
.
Header
.
Add
(
"Content-Type"
,
"application/json"
)
resp
,
err
:=
v
.
client
.
Do
(
req
)
log
.
Printf
(
"Post-Processor Vagrant Cloud API Response:
\n\n
%s"
,
resp
)
return
resp
,
err
}
func
(
v
VagrantCloudClient
)
Put
(
path
string
)
(
*
http
.
Response
,
error
)
{
params
:=
url
.
Values
{}
params
.
Set
(
"access_token"
,
v
.
AccessToken
)
reqUrl
:=
fmt
.
Sprintf
(
"%s/%s?%s"
,
v
.
BaseURL
,
path
,
params
.
Encode
())
// Scrub API key for logs
scrubbedUrl
:=
strings
.
Replace
(
reqUrl
,
v
.
AccessToken
,
"ACCESS_TOKEN"
,
-
1
)
log
.
Printf
(
"Post-Processor Vagrant Cloud API PUT: %s"
,
scrubbedUrl
)
req
,
err
:=
http
.
NewRequest
(
"PUT"
,
reqUrl
,
nil
)
req
.
Header
.
Add
(
"Content-Type"
,
"application/json"
)
resp
,
err
:=
v
.
client
.
Do
(
req
)
log
.
Printf
(
"Post-Processor Vagrant Cloud API Response:
\n\n
%s"
,
resp
)
return
resp
,
err
}
post-processor/vagrant-cloud/post-processor.go
0 → 100644
View file @
3bdd9ccb
// vagrant_cloud implements the packer.PostProcessor interface and adds a
// post-processor that uploads artifacts from the vagrant post-processor
// to Vagrant Cloud (vagrantcloud.com)
package
vagrantcloud
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"log"
"strings"
)
const
VAGRANT_CLOUD_URL
=
"https://vagrantcloud.com/api/v1"
type
Config
struct
{
common
.
PackerConfig
`mapstructure:",squash"`
Tag
string
`mapstructure:"box_tag"`
Version
string
`mapstructure:"version"`
VersionDescription
string
`mapstructure:"version_description"`
NoRelease
bool
`mapstructure:"no_release"`
AccessToken
string
`mapstructure:"access_token"`
VagrantCloudUrl
string
`mapstructure:"vagrant_cloud_url"`
tpl
*
packer
.
ConfigTemplate
}
type
PostProcessor
struct
{
config
Config
client
*
VagrantCloudClient
runner
multistep
.
Runner
}
func
(
p
*
PostProcessor
)
Configure
(
raws
...
interface
{})
error
{
_
,
err
:=
common
.
DecodeConfig
(
&
p
.
config
,
raws
...
)
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
,
err
=
packer
.
NewConfigTemplate
()
if
err
!=
nil
{
return
err
}
p
.
config
.
tpl
.
UserVars
=
p
.
config
.
PackerUserVars
// Default configuration
if
p
.
config
.
VagrantCloudUrl
==
""
{
p
.
config
.
VagrantCloudUrl
=
VAGRANT_CLOUD_URL
}
// Accumulate any errors
errs
:=
new
(
packer
.
MultiError
)
// required configuration
templates
:=
map
[
string
]
*
string
{
"box_tag"
:
&
p
.
config
.
Tag
,
"version"
:
&
p
.
config
.
Version
,
"access_token"
:
&
p
.
config
.
AccessToken
,
}
for
key
,
ptr
:=
range
templates
{
if
*
ptr
==
""
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"%s must be set"
,
key
))
}
}
// Template process
for
key
,
ptr
:=
range
templates
{
*
ptr
,
err
=
p
.
config
.
tpl
.
Process
(
*
ptr
,
nil
)
if
err
!=
nil
{
errs
=
packer
.
MultiErrorAppend
(
errs
,
fmt
.
Errorf
(
"Error processing %s: %s"
,
key
,
err
))
}
}
if
len
(
errs
.
Errors
)
>
0
{
return
errs
}
return
nil
}
func
(
p
*
PostProcessor
)
PostProcess
(
ui
packer
.
Ui
,
artifact
packer
.
Artifact
)
(
packer
.
Artifact
,
bool
,
error
)
{
// Only accepts input from the vagrant post-processor
if
artifact
.
BuilderId
()
!=
"mitchellh.post-processor.vagrant"
{
return
nil
,
false
,
fmt
.
Errorf
(
"Unknown artifact type, requires box from vagrant post-processor: %s"
,
artifact
.
BuilderId
())
}
// We assume that there is only one .box file to upload
if
!
strings
.
HasSuffix
(
artifact
.
Files
()[
0
],
".box"
)
{
return
nil
,
false
,
fmt
.
Errorf
(
"Unknown files in artifact from vagrant post-processor: %s"
,
artifact
.
Files
())
}
// create the HTTP client
p
.
client
=
VagrantCloudClient
{}
.
New
(
p
.
config
.
VagrantCloudUrl
,
p
.
config
.
AccessToken
)
// The name of the provider for vagrant cloud, and vagrant
providerName
:=
providerFromBuilderName
(
artifact
.
Id
())
// Set up the state
state
:=
new
(
multistep
.
BasicStateBag
)
state
.
Put
(
"config"
,
p
.
config
)
state
.
Put
(
"client"
,
p
.
client
)
state
.
Put
(
"artifact"
,
artifact
)
state
.
Put
(
"artifactFilePath"
,
artifact
.
Files
()[
0
])
state
.
Put
(
"ui"
,
ui
)
state
.
Put
(
"providerName"
,
providerName
)
// Build the steps
steps
:=
[]
multistep
.
Step
{
new
(
stepVerifyBox
),
new
(
stepCreateVersion
),
new
(
stepCreateProvider
),
new
(
stepPrepareUpload
),
new
(
stepUpload
),
new
(
stepVerifyUpload
),
new
(
stepReleaseVersion
),
}
// Run the steps
if
p
.
config
.
PackerDebug
{
p
.
runner
=
&
multistep
.
DebugRunner
{
Steps
:
steps
,
PauseFn
:
common
.
MultistepDebugFn
(
ui
),
}
}
else
{
p
.
runner
=
&
multistep
.
BasicRunner
{
Steps
:
steps
}
}
p
.
runner
.
Run
(
state
)
// If there was an error, return that
if
rawErr
,
ok
:=
state
.
GetOk
(
"error"
);
ok
{
return
nil
,
false
,
rawErr
.
(
error
)
}
return
NewArtifact
(
providerName
,
p
.
config
.
Tag
),
true
,
nil
}
// Runs a cleanup if the post processor fails to upload
func
(
p
*
PostProcessor
)
Cancel
()
{
if
p
.
runner
!=
nil
{
log
.
Println
(
"Cancelling the step runner..."
)
p
.
runner
.
Cancel
()
}
}
// converts a packer builder name to the corresponding vagrant
// provider
func
providerFromBuilderName
(
name
string
)
string
{
switch
name
{
case
"aws"
:
return
"aws"
case
"digitalocean"
:
return
"digitalocean"
case
"virtualbox"
:
return
"virtualbox"
case
"vmware"
:
return
"vmware_desktop"
case
"parallels"
:
return
"parallels"
default
:
return
name
}
}
post-processor/vagrant-cloud/post-processor_test.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"bytes"
"github.com/mitchellh/packer/packer"
"testing"
)
func
testGoodConfig
()
map
[
string
]
interface
{}
{
return
map
[
string
]
interface
{}{
"access_token"
:
"foo"
,
"version_description"
:
"bar"
,
"box_tag"
:
"hashicorp/precise64"
,
"version"
:
"0.5"
,
}
}
func
testBadConfig
()
map
[
string
]
interface
{}
{
return
map
[
string
]
interface
{}{
"access_token"
:
"foo"
,
"box_tag"
:
"baz"
,
"version_description"
:
"bar"
,
}
}
func
TestPostProcessor_Configure_Good
(
t
*
testing
.
T
)
{
var
p
PostProcessor
if
err
:=
p
.
Configure
(
testGoodConfig
());
err
!=
nil
{
t
.
Fatalf
(
"err: %s"
,
err
)
}
}
func
TestPostProcessor_Configure_Bad
(
t
*
testing
.
T
)
{
var
p
PostProcessor
if
err
:=
p
.
Configure
(
testBadConfig
());
err
==
nil
{
t
.
Fatalf
(
"should have err"
)
}
}
func
testUi
()
*
packer
.
BasicUi
{
return
&
packer
.
BasicUi
{
Reader
:
new
(
bytes
.
Buffer
),
Writer
:
new
(
bytes
.
Buffer
),
}
}
func
TestPostProcessor_ImplementsPostProcessor
(
t
*
testing
.
T
)
{
var
_
packer
.
PostProcessor
=
new
(
PostProcessor
)
}
func
TestproviderFromBuilderName
(
t
*
testing
.
T
)
{
if
providerFromBuilderName
(
"foobar"
)
!=
"foobar"
{
t
.
Fatal
(
"should copy unknown provider"
)
}
if
providerFromBuilderName
(
"vmware"
)
!=
"vmware_desktop"
{
t
.
Fatal
(
"should convert provider"
)
}
}
post-processor/vagrant-cloud/step_create_provider.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type
Provider
struct
{
Name
string
`json:"name"`
HostedToken
string
`json:"hosted_token,omitempty"`
UploadUrl
string
`json:"upload_url,omitempty"`
}
type
stepCreateProvider
struct
{
name
string
// the name of the provider
}
func
(
s
*
stepCreateProvider
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
box
:=
state
.
Get
(
"box"
)
.
(
*
Box
)
version
:=
state
.
Get
(
"version"
)
.
(
*
Version
)
providerName
:=
state
.
Get
(
"providerName"
)
.
(
string
)
path
:=
fmt
.
Sprintf
(
"box/%s/version/%v/providers"
,
box
.
Tag
,
version
.
Number
)
provider
:=
&
Provider
{
Name
:
providerName
}
// Wrap the provider in a provider object for the API
wrapper
:=
make
(
map
[
string
]
interface
{})
wrapper
[
"provider"
]
=
provider
ui
.
Say
(
fmt
.
Sprintf
(
"Creating provider: %s"
,
providerName
))
resp
,
err
:=
client
.
Post
(
path
,
wrapper
)
if
err
!=
nil
||
(
resp
.
StatusCode
!=
200
)
{
cloudErrors
:=
&
VagrantCloudErrors
{}
err
=
decodeBody
(
resp
,
cloudErrors
)
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error creating provider: %s"
,
cloudErrors
.
FormatErrors
()))
return
multistep
.
ActionHalt
}
if
err
=
decodeBody
(
resp
,
provider
);
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error parsing provider response: %s"
,
err
))
return
multistep
.
ActionHalt
}
// Save the name for cleanup
s
.
name
=
provider
.
Name
state
.
Put
(
"provider"
,
provider
)
return
multistep
.
ActionContinue
}
func
(
s
*
stepCreateProvider
)
Cleanup
(
state
multistep
.
StateBag
)
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
box
:=
state
.
Get
(
"box"
)
.
(
*
Box
)
version
:=
state
.
Get
(
"version"
)
.
(
*
Version
)
// If we didn't save the provider name, it likely doesn't exist
if
s
.
name
==
""
{
ui
.
Say
(
"Cleaning up provider"
)
ui
.
Message
(
"Provider was not created, not deleting"
)
return
}
_
,
cancelled
:=
state
.
GetOk
(
multistep
.
StateCancelled
)
_
,
halted
:=
state
.
GetOk
(
multistep
.
StateHalted
)
// Return if we didn't cancel or halt, and thus need
// no cleanup
if
!
cancelled
&&
!
halted
{
return
}
ui
.
Say
(
"Cleaning up provider"
)
ui
.
Message
(
fmt
.
Sprintf
(
"Deleting provider: %s"
,
s
.
name
))
path
:=
fmt
.
Sprintf
(
"box/%s/version/%v/provider/%s"
,
box
.
Tag
,
version
.
Number
,
s
.
name
)
// No need for resp from the cleanup DELETE
_
,
err
:=
client
.
Delete
(
path
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error destroying provider: %s"
,
err
))
}
}
post-processor/vagrant-cloud/step_create_version.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type
Version
struct
{
Version
string
`json:"version"`
Description
string
`json:"description,omitempty"`
Number
uint
`json:"number,omitempty"`
}
type
stepCreateVersion
struct
{
number
uint
// number of the version, if needed in cleanup
}
func
(
s
*
stepCreateVersion
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
box
:=
state
.
Get
(
"box"
)
.
(
*
Box
)
ui
.
Say
(
fmt
.
Sprintf
(
"Creating version: %s"
,
config
.
Version
))
if
hasVersion
,
v
:=
box
.
HasVersion
(
config
.
Version
);
hasVersion
{
ui
.
Message
(
fmt
.
Sprintf
(
"Version exists, skipping creation"
))
state
.
Put
(
"version"
,
v
)
return
multistep
.
ActionContinue
}
path
:=
fmt
.
Sprintf
(
"box/%s/versions"
,
box
.
Tag
)
version
:=
&
Version
{
Version
:
config
.
Version
,
Description
:
config
.
VersionDescription
}
// Wrap the version in a version object for the API
wrapper
:=
make
(
map
[
string
]
interface
{})
wrapper
[
"version"
]
=
version
resp
,
err
:=
client
.
Post
(
path
,
wrapper
)
if
err
!=
nil
||
(
resp
.
StatusCode
!=
200
)
{
cloudErrors
:=
&
VagrantCloudErrors
{}
err
=
decodeBody
(
resp
,
cloudErrors
)
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error creating version: %s"
,
cloudErrors
.
FormatErrors
()))
return
multistep
.
ActionHalt
}
if
err
=
decodeBody
(
resp
,
version
);
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error parsing version response: %s"
,
err
))
return
multistep
.
ActionHalt
}
// Save the number for cleanup
s
.
number
=
version
.
Number
state
.
Put
(
"version"
,
version
)
return
multistep
.
ActionContinue
}
func
(
s
*
stepCreateVersion
)
Cleanup
(
state
multistep
.
StateBag
)
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
box
:=
state
.
Get
(
"box"
)
.
(
*
Box
)
// If we didn't save the version number, it likely doesn't exist or
// already existed
if
s
.
number
==
0
{
ui
.
Message
(
"Version was not created or previously existed, not deleting"
)
return
}
_
,
cancelled
:=
state
.
GetOk
(
multistep
.
StateCancelled
)
_
,
halted
:=
state
.
GetOk
(
multistep
.
StateHalted
)
// Return if we didn't cancel or halt, and thus need
// no cleanup
if
!
cancelled
&&
!
halted
{
return
}
path
:=
fmt
.
Sprintf
(
"box/%s/version/%v"
,
box
.
Tag
,
s
.
number
)
ui
.
Say
(
"Cleaning up version"
)
ui
.
Message
(
fmt
.
Sprintf
(
"Deleting version: %s"
,
config
.
Version
))
// No need for resp from the cleanup DELETE
_
,
err
:=
client
.
Delete
(
path
)
if
err
!=
nil
{
ui
.
Error
(
fmt
.
Sprintf
(
"Error destroying version: %s"
,
err
))
}
}
post-processor/vagrant-cloud/step_prepare_upload.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type
Upload
struct
{
Token
string
`json:"token"`
UploadPath
string
`json:"upload_path"`
}
type
stepPrepareUpload
struct
{
}
func
(
s
*
stepPrepareUpload
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
box
:=
state
.
Get
(
"box"
)
.
(
*
Box
)
version
:=
state
.
Get
(
"version"
)
.
(
*
Version
)
provider
:=
state
.
Get
(
"provider"
)
.
(
*
Provider
)
artifactFilePath
:=
state
.
Get
(
"artifactFilePath"
)
.
(
string
)
path
:=
fmt
.
Sprintf
(
"box/%s/version/%v/provider/%s/upload"
,
box
.
Tag
,
version
.
Number
,
provider
.
Name
)
upload
:=
&
Upload
{}
ui
.
Say
(
fmt
.
Sprintf
(
"Preparing upload of box: %s"
,
artifactFilePath
))
resp
,
err
:=
client
.
Get
(
path
)
if
err
!=
nil
||
(
resp
.
StatusCode
!=
200
)
{
cloudErrors
:=
&
VagrantCloudErrors
{}
err
=
decodeBody
(
resp
,
cloudErrors
)
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error preparing upload: %s"
,
cloudErrors
.
FormatErrors
()))
return
multistep
.
ActionHalt
}
if
err
=
decodeBody
(
resp
,
upload
);
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error parsing upload response: %s"
,
err
))
return
multistep
.
ActionHalt
}
ui
.
Message
(
fmt
.
Sprintf
(
"Box upload prepared with token %s"
,
upload
.
Token
))
// Save the upload details to the state
state
.
Put
(
"upload"
,
upload
)
return
multistep
.
ActionContinue
}
func
(
s
*
stepPrepareUpload
)
Cleanup
(
state
multistep
.
StateBag
)
{
// No cleanup
}
post-processor/vagrant-cloud/step_release_version.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type
stepReleaseVersion
struct
{
}
func
(
s
*
stepReleaseVersion
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
box
:=
state
.
Get
(
"box"
)
.
(
*
Box
)
version
:=
state
.
Get
(
"version"
)
.
(
*
Version
)
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
.
Say
(
fmt
.
Sprintf
(
"Releasing version: %s"
,
version
.
Version
))
if
config
.
NoRelease
{
ui
.
Message
(
"Not releasing version due to configuration"
)
return
multistep
.
ActionContinue
}
path
:=
fmt
.
Sprintf
(
"box/%s/version/%v/release"
,
box
.
Tag
,
version
.
Number
)
resp
,
err
:=
client
.
Put
(
path
)
if
err
!=
nil
||
(
resp
.
StatusCode
!=
200
)
{
cloudErrors
:=
&
VagrantCloudErrors
{}
err
=
decodeBody
(
resp
,
cloudErrors
)
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error releasing version: %s"
,
cloudErrors
.
FormatErrors
()))
return
multistep
.
ActionHalt
}
ui
.
Message
(
fmt
.
Sprintf
(
"Version successfully released and available"
))
return
multistep
.
ActionContinue
}
func
(
s
*
stepReleaseVersion
)
Cleanup
(
state
multistep
.
StateBag
)
{
// No cleanup
}
post-processor/vagrant-cloud/step_upload.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type
stepUpload
struct
{
}
func
(
s
*
stepUpload
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
upload
:=
state
.
Get
(
"upload"
)
.
(
*
Upload
)
artifactFilePath
:=
state
.
Get
(
"artifactFilePath"
)
.
(
string
)
url
:=
upload
.
UploadPath
ui
.
Say
(
fmt
.
Sprintf
(
"Uploading box: %s"
,
artifactFilePath
))
ui
.
Message
(
"Depending on your internet connection and the size of the box, this may take some time"
)
resp
,
err
:=
client
.
Upload
(
artifactFilePath
,
url
)
if
err
!=
nil
||
(
resp
.
StatusCode
!=
200
)
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error uploading Box: %s"
,
err
))
return
multistep
.
ActionHalt
}
ui
.
Message
(
"Box succesfully uploaded"
)
return
multistep
.
ActionContinue
}
func
(
s
*
stepUpload
)
Cleanup
(
state
multistep
.
StateBag
)
{
// No cleanup
}
post-processor/vagrant-cloud/step_verify_box.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
type
Box
struct
{
Tag
string
`json:"tag"`
Versions
[]
*
Version
`json:"versions"`
}
func
(
b
*
Box
)
HasVersion
(
version
string
)
(
bool
,
*
Version
)
{
for
_
,
v
:=
range
b
.
Versions
{
if
v
.
Version
==
version
{
return
true
,
v
}
}
return
false
,
nil
}
type
stepVerifyBox
struct
{
}
func
(
s
*
stepVerifyBox
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
config
:=
state
.
Get
(
"config"
)
.
(
Config
)
ui
.
Say
(
fmt
.
Sprintf
(
"Verifying box is accessible: %s"
,
config
.
Tag
))
path
:=
fmt
.
Sprintf
(
"box/%s"
,
config
.
Tag
)
resp
,
err
:=
client
.
Get
(
path
)
if
err
!=
nil
||
(
resp
.
StatusCode
!=
200
)
{
cloudErrors
:=
&
VagrantCloudErrors
{}
err
=
decodeBody
(
resp
,
cloudErrors
)
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error retrieving box: %s"
,
cloudErrors
.
FormatErrors
()))
return
multistep
.
ActionHalt
}
box
:=
&
Box
{}
if
err
=
decodeBody
(
resp
,
box
);
err
!=
nil
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Error parsing box response: %s"
,
err
))
return
multistep
.
ActionHalt
}
if
box
.
Tag
!=
config
.
Tag
{
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Could not verify box: %s"
,
config
.
Tag
))
return
multistep
.
ActionHalt
}
ui
.
Message
(
"Box accessible and matches tag"
)
// Keep the box in state for later
state
.
Put
(
"box"
,
box
)
// Box exists and is accessible
return
multistep
.
ActionContinue
}
func
(
s
*
stepVerifyBox
)
Cleanup
(
state
multistep
.
StateBag
)
{
// no cleanup needed
}
post-processor/vagrant-cloud/step_verify_upload.go
0 → 100644
View file @
3bdd9ccb
package
vagrantcloud
import
(
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"time"
)
type
stepVerifyUpload
struct
{
}
func
(
s
*
stepVerifyUpload
)
Run
(
state
multistep
.
StateBag
)
multistep
.
StepAction
{
client
:=
state
.
Get
(
"client"
)
.
(
*
VagrantCloudClient
)
ui
:=
state
.
Get
(
"ui"
)
.
(
packer
.
Ui
)
box
:=
state
.
Get
(
"box"
)
.
(
*
Box
)
version
:=
state
.
Get
(
"version"
)
.
(
*
Version
)
upload
:=
state
.
Get
(
"upload"
)
.
(
*
Upload
)
provider
:=
state
.
Get
(
"provider"
)
.
(
*
Provider
)
path
:=
fmt
.
Sprintf
(
"box/%s/version/%v/provider/%s"
,
box
.
Tag
,
version
.
Number
,
provider
.
Name
)
providerCheck
:=
&
Provider
{}
ui
.
Say
(
fmt
.
Sprintf
(
"Verifying provider upload: %s"
,
provider
.
Name
))
done
:=
make
(
chan
struct
{})
defer
close
(
done
)
result
:=
make
(
chan
error
,
1
)
go
func
()
{
attempts
:=
0
for
{
attempts
+=
1
log
.
Printf
(
"Checking token match for provider.. (attempt: %d)"
,
attempts
)
resp
,
err
:=
client
.
Get
(
path
)
if
err
!=
nil
||
(
resp
.
StatusCode
!=
200
)
{
cloudErrors
:=
&
VagrantCloudErrors
{}
err
=
decodeBody
(
resp
,
cloudErrors
)
err
=
fmt
.
Errorf
(
"Error retrieving provider: %s"
,
cloudErrors
.
FormatErrors
())
result
<-
err
return
}
if
err
=
decodeBody
(
resp
,
providerCheck
);
err
!=
nil
{
err
=
fmt
.
Errorf
(
"Error parsing provider response: %s"
,
err
)
result
<-
err
return
}
if
err
!=
nil
{
result
<-
err
return
}
if
upload
.
Token
==
providerCheck
.
HostedToken
{
// success!
result
<-
nil
return
}
// Wait 3 seconds in between
time
.
Sleep
(
3
*
time
.
Second
)
// Verify we shouldn't exit
select
{
case
<-
done
:
// We finished, so just exit the goroutine
return
default
:
// Keep going
}
}
}()
ui
.
Message
(
"Waiting for upload token match"
)
log
.
Printf
(
"Waiting for up to 600 seconds for provider hosted token to match %s"
,
upload
.
Token
)
select
{
case
err
:=
<-
result
:
if
err
!=
nil
{
state
.
Put
(
"error"
,
err
)
return
multistep
.
ActionHalt
}
ui
.
Message
(
fmt
.
Sprintf
(
"Upload succesfully verified with token %s"
,
providerCheck
.
HostedToken
))
log
.
Printf
(
"Box succesfully verified %s == %s"
,
upload
.
Token
,
providerCheck
.
HostedToken
)
return
multistep
.
ActionContinue
case
<-
time
.
After
(
600
*
time
.
Second
)
:
state
.
Put
(
"error"
,
fmt
.
Errorf
(
"Timeout while waiting to for upload to verify token '%s'"
,
upload
.
Token
))
return
multistep
.
ActionHalt
}
}
func
(
s
*
stepVerifyUpload
)
Cleanup
(
state
multistep
.
StateBag
)
{
// No cleanup
}
post-processor/vagrant/artifact.go
View file @
3bdd9ccb
...
...
@@ -28,7 +28,7 @@ func (a *Artifact) Files() []string {
}
func
(
a
*
Artifact
)
Id
()
string
{
return
""
return
a
.
Provider
}
func
(
a
*
Artifact
)
String
()
string
{
...
...
post-processor/vagrant/artifact_test.go
View file @
3bdd9ccb
...
...
@@ -12,3 +12,10 @@ func TestArtifact_ImplementsArtifact(t *testing.T) {
t
.
Fatalf
(
"Artifact should be a Artifact"
)
}
}
func
TestArtifact_Id
(
t
*
testing
.
T
)
{
artifact
:=
NewArtifact
(
"vmware"
,
"./"
)
if
artifact
.
Id
()
!=
"vmware"
{
t
.
Fatalf
(
"should return name as Id"
)
}
}
website/source/docs/post-processors/vagrant-cloud.html.markdown
0 → 100644
View file @
3bdd9ccb
---
layout
:
"
docs"
page_title
:
"
Vagrant
Cloud
Post-Processor"
---
# Vagrant Cloud Post-Processor
Type:
`vagrant-cloud`
The Vagrant Cloud post-processor recieves a Vagrant box from the
`vagrant`
post-processor and pushes it to Vagrant Cloud.
[
Vagrant Cloud
](
https://vagrantcloud.com
)
hosts and serves boxes to Vagrant, allowing you to version and distribute
boxes to an organization in a simple way.
You'll need to be familiar with Vagrant Cloud, have an upgraded account
to enable box hosting, and be distributing your box via the
[
shorthand name
](
http://docs.vagrantup.com/v2/cli/box.html
)
configuration.
## Workflow
It's important to understand the workflow that using this post-processor
enforces in order to take full advantage of Vagrant and Vagrant Cloud.
The use of this processor assume that you currently distribute, or plan
to distrubute, boxes via Vagrant Cloud. It also assumes you create Vagrant
Boxes and deliver them to your team in some fashion.
Here is an example workflow:
1.
You use Packer to build a Vagrant Box for the
`virtualbox`
provider
2.
The
`vagrant-cloud`
post-processor is configured to point to the box
`hashicorp/foobar`
on Vagrant Cloud
via the
`box_tag`
configuration
2.
The post-processor receives the box from the
`vagrant`
post-processor
3.
It then creates the configured version, or verifies the existence of it, on Vagrant Cloud
4.
A provider matching the name of the Vagrant provider is then created
5.
The box is uploaded to Vagrant Cloud
6.
The upload is verified
7.
The version is released and available to users of the box
## Configuration
The configuration allows you to specify the target box that you have
access to on Vagrant Cloud, as well as authentication and version information.
### Required:
*
`access_token`
(string) - Your access token for the Vagrant Cloud API.
This can be generated on your
[
tokens page
](
https://vagrantcloud.com/account/tokens
)
.
*
`box_tag`
(string) - The shorthand tag for your box that maps to
Vagrant Cloud, i.e
`hashicorp/precise64`
for
`vagrantcloud.com/hashicorp/precise64`
*
`version`
(string) - The version number, typically incrementing a previous version.
The version string is validated based on
[
Semantic Versioning
](
http://semver.org/
)
. The string must match
a pattern that could be semver, and doesn't validate that the version comes after
your previous versions.
### Optional:
*
`version_description`
(string) - Optionally markdown text used as a full-length
and in-depth description of the version, typically for denoting changes introduced
*
`no_release`
(string) - If set to true, does not release the version
on Vagrant Cloud, making it active. You can manually release the version
via the API or Web UI. Defaults to false.
*
`vagrant_cloud_url`
(string) - Override the base URL for Vagrant Cloud. This
is useful if you're using Vagrant Private Cloud in your own network. Defaults
to
`https://vagrantcloud.com/api/v1`
## Use with Vagrant Post-Processor
You'll need to use the Vagrant post-processor before using this post-processor.
An example configuration is below. Note the use of the array specifying
the execution order.
```
json
{
"variables"
:
{
"version"
:
""
,
"cloud_token"
:
""
},
"builders"
:
[{
...
}],
"post-processors"
:
[
[{
"type"
:
"vagrant"
,
"include"
:
[
"image.iso"
],
"vagrantfile_template"
:
"vagrantfile.tpl"
,
"output"
:
"proxycore_{{.Provider}}.box"
},
{
"type"
:
"vagrant-cloud"
,
"box_tag"
:
"hashicorp/precise64"
,
"access_token"
:
"{{user `cloud_token`}}"
,
"version"
:
"{{user `version`}}"
}]
]
}
```
website/source/layouts/docs.erb
View file @
3bdd9ccb
...
...
@@ -61,6 +61,7 @@
<li><a
href=
"/docs/post-processors/docker-import.html"
>
docker-import
</a></li>
<li><a
href=
"/docs/post-processors/docker-push.html"
>
docker-push
</a></li>
<li><a
href=
"/docs/post-processors/vagrant.html"
>
Vagrant
</a></li>
<li><a
href=
"/docs/post-processors/vagrant-cloud.html"
>
Vagrant Cloud
</a></li>
<li><a
href=
"/docs/post-processors/vsphere.html"
>
vSphere
</a></li>
</ul>
...
...
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