Merge branch 'set_azure_custom_res_names' of github.com:vijayrajah/packer into set_azure_custom_res_names
This commit is contained in:
commit
56bf8bd686
|
@ -158,6 +158,28 @@ jobs:
|
|||
at: .
|
||||
- run: |
|
||||
ghr -prerelease -t ${GITHUB_TOKEN_AZR} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${CIRCLE_TAG} ./pkg/
|
||||
build-website-docker-image:
|
||||
docker:
|
||||
- image: circleci/buildpack-deps
|
||||
shell: /usr/bin/env bash -euo pipefail -c
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
- run:
|
||||
name: Build Docker Image if Necessary
|
||||
command: |
|
||||
IMAGE_TAG=$(cat website/Dockerfile website/package-lock.json | sha256sum | awk '{print $1;}')
|
||||
echo "Using $IMAGE_TAG"
|
||||
if curl https://hub.docker.com/v2/repositories/hashicorp/packer-website/tags/$IMAGE_TAG -fsL > /dev/null; then
|
||||
echo "Dependencies have not changed, not building a new website docker image."
|
||||
else
|
||||
cd website/
|
||||
docker build -t hashicorp/packer-website:$IMAGE_TAG .
|
||||
docker tag hashicorp/packer-website:$IMAGE_TAG hashicorp/packer-website:latest
|
||||
docker login -u $WEBSITE_DOCKER_USER -p $WEBSITE_DOCKER_PASS
|
||||
docker push hashicorp/packer-website
|
||||
fi
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
test:
|
||||
|
@ -218,3 +240,10 @@ workflows:
|
|||
ignore: /.*/
|
||||
tags:
|
||||
only: nightly
|
||||
build_website_docker_image:
|
||||
jobs:
|
||||
- build-website-docker-image:
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
|
|
@ -15,20 +15,20 @@ can quickly merge or address your contributions.
|
|||
|
||||
### Reporting an Issue
|
||||
|
||||
* Make sure you test against the latest released version. It is possible we
|
||||
- Make sure you test against the latest released version. It is possible we
|
||||
already fixed the bug you're experiencing.
|
||||
|
||||
* Run the command with debug output with the environment variable `PACKER_LOG`.
|
||||
- Run the command with debug output with the environment variable `PACKER_LOG`.
|
||||
For example: `PACKER_LOG=1 packer build template.json`. Take the _entire_
|
||||
output and create a [gist](https://gist.github.com) for linking to in your
|
||||
issue. Packer should strip sensitive keys from the output, but take a look
|
||||
through just in case.
|
||||
|
||||
* Provide a reproducible test case. If a contributor can't reproduce an issue,
|
||||
- Provide a reproducible test case. If a contributor can't reproduce an issue,
|
||||
then it dramatically lowers the chances it'll get fixed. And in some cases,
|
||||
the issue will eventually be closed.
|
||||
|
||||
* Respond promptly to any questions made by the Packer team to your issue. Stale
|
||||
- Respond promptly to any questions made by the Packer team to your issue. Stale
|
||||
issues will be closed.
|
||||
|
||||
### Issue Lifecycle
|
||||
|
@ -86,23 +86,23 @@ The instructions below are for go 1.7. or later.
|
|||
submitting a pull-request.
|
||||
|
||||
### Windows Systems
|
||||
|
||||
On windows systems you need at least the [MinGW Tools](http://www.mingw.org/), e.g. install via [choco](https://chocolatey.org/):
|
||||
|
||||
```
|
||||
choco install mingw -y
|
||||
```
|
||||
|
||||
This installs the GCC compiler, as well as a ```mingw32-make``` which can be used wherever
|
||||
this documentation mentions ```make```
|
||||
This installs the GCC compiler, as well as a `mingw32-make` which can be used wherever
|
||||
this documentation mentions `make`
|
||||
|
||||
when building using ```go``` you also need to mention the windows
|
||||
when building using `go` you also need to mention the windows
|
||||
executable extension
|
||||
|
||||
```
|
||||
go build -o bin/packer.exe
|
||||
```
|
||||
|
||||
|
||||
### Opening an Pull Request
|
||||
|
||||
Thank you for contributing! When you are ready to open a pull-request, you will
|
||||
|
@ -162,7 +162,6 @@ to use `git push ...`.
|
|||
6. In rare cases, we might decide that a PR should be closed without merging.
|
||||
We'll make sure to provide clear reasoning when this happens.
|
||||
|
||||
|
||||
### Tips for Working on Packer
|
||||
|
||||
#### Getting Your Pull Requests Merged Faster
|
||||
|
@ -250,7 +249,7 @@ does not attempt to track the latest version for each dependency.
|
|||
|
||||
Packer relies on `go generate` to generate a [peg parser for boot
|
||||
commands](https://github.com/hashicorp/packer/blob/master/common/bootcommand/boot_command.go),
|
||||
[docs](https://github.com/hashicorp/packer/blob/master/website/source/partials/builder/amazon/chroot/_Config-not-required.html.md)
|
||||
[docs](https://github.com/hashicorp/packer/blob/master/website/pages/partials/builder/amazon/chroot/_Config-not-required.mdx)
|
||||
and HCL2's bridging code. Packer's testing suite will run `make check-generate`
|
||||
to check that all the generated files Packer needs are what they should be.
|
||||
`make generate` re-generates all these file and can take a while depending on
|
||||
|
@ -266,11 +265,13 @@ Packer relies on [golangci-lint](https://github.com/golangci/golangci-lint) for
|
|||
The main configuration for golangci-lint is the `.golangci.yml` in the project root. See `golangci-lint --help` for a list of flags that can be used to override the default configuration.
|
||||
|
||||
Run golangci-lint on the entire Packer code base.
|
||||
|
||||
```
|
||||
make lint
|
||||
```
|
||||
|
||||
Run golangci-lint on a single pkg or directory; PKG_NAME expands to /builder/amazon/...
|
||||
|
||||
```
|
||||
make lint PKG_NAME=builder/amazon
|
||||
```
|
||||
|
@ -328,6 +329,205 @@ Acceptance tests typically require other environment variables to be set for
|
|||
things such as API tokens and keys. Each test should error and tell you which
|
||||
credentials are missing, so those are not documented here.
|
||||
|
||||
#### Running Provisioners Acceptance Tests
|
||||
|
||||
**Warning:** The acceptance tests create/destroy/modify _real resources_, which
|
||||
may incur costs for real money. In the presence of a bug, it is possible that
|
||||
resources may be left behind, which can cost money even though you were not
|
||||
using them. We recommend running tests in an account used only for that purpose
|
||||
so it is easy to see if there are any dangling resources, and so production
|
||||
resources are not accidentally destroyed or overwritten during testing.
|
||||
Also, these typically require an API key (AWS, GCE), or additional software
|
||||
to be installed on your computer (VirtualBox, VMware).
|
||||
|
||||
To run the Provisioners Acceptance Tests you should use both **ACC_TEST_BUILDERS** and **ACC_TEST_PROVISIONERS** variables to
|
||||
tell which provisioner and builder the test should be run against.
|
||||
|
||||
Examples of usage:
|
||||
|
||||
- Run the Shell provisioner acceptance tests against the Amazon EBS builder.
|
||||
```
|
||||
ACC_TEST_BUILDERS=amazon-ebs ACC_TEST_PROVISIONERS=shell go test ./provisioner/shell/... -v -timeout=1h
|
||||
```
|
||||
- Do the same but using the Makefile
|
||||
```
|
||||
ACC_TEST_BUILDERS=amazon-ebs ACC_TEST_PROVISIONERS=shell make provisioners-acctest
|
||||
```
|
||||
- Run the all Shell and Powershell provisioners acceptance tests against the Amazon EBS builder.
|
||||
```
|
||||
ACC_TEST_BUILDERS=amazon-ebs ACC_TEST_PROVISIONERS=shell,powershell make provisioners-acctest
|
||||
```
|
||||
- Run the all provisioners acceptance tests against the Amazon EBS builder.
|
||||
```
|
||||
ACC_TEST_BUILDERS=amazon-ebs ACC_TEST_PROVISIONERS=all make provisioners-acctest
|
||||
```
|
||||
- Run the all provisioners acceptance tests against all builders whenever they are compatible.
|
||||
```
|
||||
ACC_TEST_BUILDERS=all ACC_TEST_PROVISIONERS=all make provisioners-acctest
|
||||
```
|
||||
|
||||
Both **ACC_TEST_BUILDERS** and **ACC_TEST_PROVISIONERS** allows defining a list of builders and provisioners separated by comma
|
||||
(e.g. `ACC_TEST_BUILDERS=amazon-ebs,virtualbox-iso`)
|
||||
|
||||
|
||||
#### Writing Provisioner Acceptance Tests
|
||||
|
||||
Packer has an already implemented structure that will run the provisioner against builders and you can find it in `helper/tests/acc/provisioners.go`.
|
||||
All provisioners should use this structure in their acceptance tests.
|
||||
|
||||
To start writing a new provisioner acceptance test, you should add a test file named as `provisioner_acc_test.go` in the provisioner folder
|
||||
and the package should be `<provisioner>_test`. This file should have a struct that will implement the ProvisionerAcceptance interface.
|
||||
|
||||
```go
|
||||
type ProvisionerAcceptance interface {
|
||||
GetName() string
|
||||
GetConfig() (string, error)
|
||||
GetProvisionerStore() packer.MapOfProvisioner
|
||||
IsCompatible(builder string, vmOS string) bool
|
||||
RunTest(c *command.BuildCommand, args []string) error
|
||||
}
|
||||
```
|
||||
|
||||
- **GetName()** should return the provisioner type. For example for the Shell provisioner the method returns "shell".
|
||||
|
||||
- **GetConfig()** should read a text file with the json configuration block for the provisioner and any other necessary provisioner.
|
||||
For the Shell one the file contains:
|
||||
|
||||
```
|
||||
{
|
||||
"type": "shell",
|
||||
"inline": [
|
||||
"echo {{ build `ID`}} > provisioner.{{ build `PackerRunUUID`}}.txt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"source": "provisioner.{{ build `PackerRunUUID`}}.txt",
|
||||
"destination": "provisioner.shell.{{ build `PackerRunUUID`}}.txt",
|
||||
"direction": "download"
|
||||
}
|
||||
```
|
||||
The file should be placed under the `test-fixtures` folder.
|
||||
In this case, it's necessary to use the File provisioner to validate if the Shell provisioner test is successful or not.
|
||||
This config should be returned as string that will be later merged with the builder config into a full template.
|
||||
|
||||
- **GetProvisionerStore()** this returns the provisioner store where we declare the available provisioners for running the build.
|
||||
For the Shell provisioners this is:
|
||||
```go
|
||||
func (s *ShellProvisionerAccTest) GetProvisionerStore() packer.MapOfProvisioner {
|
||||
return packer.MapOfProvisioner{
|
||||
"shell": func() (packer.Provisioner, error) { return &shell.Provisioner{}, nil },
|
||||
"file": func() (packer.Provisioner, error) { return &file.Provisioner{}, nil },
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **IsCompatible(builder string, vmOS string)** returns true or false whether the provisioner should run against a
|
||||
specific builder or/and specific OS.
|
||||
|
||||
- **RunTest(c \*command.BuildCommand, args []string)** it will actually run the build and return any error if it fails the validations.
|
||||
For the Shell provisioner this is:
|
||||
```go
|
||||
func (s *ShellProvisionerAccTest) RunTest(c *command.BuildCommand, args []string) error {
|
||||
// Provisioner specific setup
|
||||
UUID := os.Getenv("PACKER_RUN_UUID")
|
||||
if UUID == "" {
|
||||
UUID, _ = uuid.GenerateUUID()
|
||||
os.Setenv("PACKER_RUN_UUID", UUID)
|
||||
}
|
||||
file := "provisioner.shell." + UUID + ".txt"
|
||||
defer testshelper.CleanupFiles(file)
|
||||
|
||||
// Run build
|
||||
// All provisioner acc tests should contain this code and validation
|
||||
if code := c.Run(args); code != 0 {
|
||||
ui := c.Meta.Ui.(*packer.BasicUi)
|
||||
out := ui.Writer.(*bytes.Buffer)
|
||||
err := ui.ErrorWriter.(*bytes.Buffer)
|
||||
return fmt.Errorf(
|
||||
"Bad exit code.\n\nStdout:\n\n%s\n\nStderr:\n\n%s",
|
||||
out.String(),
|
||||
err.String())
|
||||
}
|
||||
|
||||
// Any other extra specific validation
|
||||
if !testshelper.FileExists(file) {
|
||||
return fmt.Errorf("Expected to find %s", file)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
After writing the struct and implementing the interface, now is time to write the test that will run all
|
||||
of this code you wrote. Your test should be like:
|
||||
|
||||
```go
|
||||
func TestShellProvisioner(t *testing.T) {
|
||||
acc.TestProvisionersPreCheck("shell", t)
|
||||
acc.TestProvisionersAgainstBuilders(new(ShellProvisionerAccTest), t)
|
||||
}
|
||||
```
|
||||
|
||||
If the environment variable **ACC_TEST_PROVISIONERS** is set as `all` or contains the provisioner type, then the test should run, otherwise the test should skip.
|
||||
In case of running it, you'll need to call the helper function `acc.TestProvisionersAgainstBuilders` passing a pointer to the test struct created above and the test testing pointer.
|
||||
|
||||
The method `TestProvisionersAgainstBuilders` will run the provisioner against all available and compatible builders. An available builder
|
||||
is the one that has the necessary code for running this type of test. In case the builder you want to run against is not available for testing, you can write it following the next steps.
|
||||
|
||||
To add a new builder to the available builders for provisioners acc testing, you'll need to create a new folder under the builder folder
|
||||
called `acceptance` and inside you create the `builder_acceptance.go` file and the package should be `<builder>_acc`. Like the provisioners, you'll need to create a struct that will
|
||||
implement the BuilderAcceptance interface.
|
||||
```go
|
||||
type BuilderAcceptance interface {
|
||||
GetConfigs() (map[string]string, error)
|
||||
GetBuilderStore() packer.MapOfBuilder
|
||||
CleanUp() error
|
||||
}
|
||||
```
|
||||
- **GetConfigs()** should read a text file with the json configuration block for the builder and return a map of configs by OS type.
|
||||
For the Amazon EBS builder the file contains:
|
||||
```
|
||||
{
|
||||
"type": "amazon-ebs",
|
||||
"ami_name": "packer-acc-test",
|
||||
"instance_type": "m1.small",
|
||||
"region": "us-east-1",
|
||||
"ssh_username": "ubuntu",
|
||||
"source_ami": "ami-0568456c",
|
||||
"force_deregister" : true,
|
||||
"tags": {
|
||||
"packer-test": "true"
|
||||
}
|
||||
}
|
||||
```
|
||||
The file should be placed under the `test-fixtures` folder.
|
||||
In case you need to make references to another file, you'll need to add the relative path to provisioners folder like:
|
||||
`../../builder/amazon/ebs/acceptance/test-fixtures/file.txt`.
|
||||
|
||||
- **GetBuilderStore()** this returns the builder store where we declare the available builders for running the build.
|
||||
For the Amazon EBS builder this is:
|
||||
```go
|
||||
func (s *AmazonEBSAccTest) GetBuilderStore() packer.MapOfBuilder {
|
||||
return packer.MapOfBuilder{
|
||||
"amazon-ebs": func() (packer.Builder, error) { return &amazonebsbuilder.Builder{}, nil },
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **CleanUp()** cleans any resource created by the builder whether local or remote.
|
||||
|
||||
Once you created the builder necessary code, the last step is adding it to the `BuildersAccTest` map in `helper/tests/acc/provisioners.go`.
|
||||
```go
|
||||
var BuildersAccTest = map[string]BuilderAcceptance{
|
||||
...
|
||||
"amazon-ebs": new(amazonEBS.AmazonEBSAccTest),
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Once you finish the steps, you should be ready to run your new provisioner acceptance test.
|
||||
|
||||
#### Debugging Plugins
|
||||
|
||||
Each packer plugin runs in a separate process and communicates via RPC over a
|
||||
|
|
|
@ -8,8 +8,8 @@ Issues on GitHub are intended to be related to bugs or feature requests, so we
|
|||
recommend using our other community resources instead of asking here if you
|
||||
have a question.
|
||||
|
||||
- Packer Guides: https://www.packer.io/guides/index.html
|
||||
- Packer Guides: https://www.packer.io/guides
|
||||
- Discussion List: https://groups.google.com/group/packer-tool
|
||||
- Any other questions can be sent to the packer section of the HashiCorp
|
||||
forum: https://discuss.hashicorp.com/c/packer
|
||||
- Packer community links: https://www.packer.io/community.html
|
||||
- Packer community links: https://www.packer.io/community
|
||||
|
|
|
@ -6,19 +6,18 @@ labels: communicator-question
|
|||
|
||||
Got one of the following errors ? See if the related guides can help.
|
||||
|
||||
* `Waiting for WinRM to become available` ?
|
||||
- `Waiting for WinRM to become available` ?
|
||||
|
||||
- See our basic WinRm Packer guide: https://www.packer.io/guides/automatic-operating-system-installs/autounattend_windows.html
|
||||
- See our basic WinRm Packer guide: https://www.packer.io/guides/automatic-operating-system-installs/autounattend_windows
|
||||
|
||||
* `Waiting for SSH to become available` ?
|
||||
|
||||
- See our basic SSH Packer guide: https://www.packer.io/guides/automatic-operating-system-installs/preseed_ubuntu.html
|
||||
- `Waiting for SSH to become available` ?
|
||||
|
||||
- See our basic SSH Packer guide: https://www.packer.io/guides/automatic-operating-system-installs/preseed_ubuntu
|
||||
|
||||
Issues on GitHub are intended to be related to bugs or feature requests, so we recommend using our other community resources instead of asking here if you have a question.
|
||||
|
||||
- Packer Guides: https://www.packer.io/guides/index.html
|
||||
- Packer Guides: https://www.packer.io/guides
|
||||
- Discussion List: https://groups.google.com/group/packer-tool
|
||||
- Any other questions can be sent to the packer section of the HashiCorp
|
||||
forum: https://discuss.hashicorp.com/c/packer
|
||||
- Packer community links: https://www.packer.io/community.html
|
||||
- Packer community links: https://www.packer.io/community
|
||||
|
|
|
@ -12,12 +12,15 @@
|
|||
|
||||
### Bug Fixes:
|
||||
* builder/amazon: Fix bug with launch_block_device_mappings in spot instances.
|
||||
[GH-8945] builder/vsphere-iso: disk_size is no longer required if storage
|
||||
is defined [GH-8975]
|
||||
[GH-8945]
|
||||
* builder/azure: Allow Managed Data Disks to be used with Azure Shared Image
|
||||
Gallery [GH-8912]
|
||||
* builder/qemu: Remove `net_device` pre-validation [GH-8979]
|
||||
* builder/vsphere-iso: disk_size is no longer required if storage is defined
|
||||
[GH-8975]
|
||||
* core: Make sure CLI variables supersede variables from var files [GH-8964]
|
||||
* provisioner/powershell: Fix integer decoding issue in the execution policy
|
||||
parser [GH-8997]
|
||||
|
||||
## 1.5.5 (March 25,2020)
|
||||
|
||||
|
|
38
CODEOWNERS
38
CODEOWNERS
|
@ -3,61 +3,61 @@
|
|||
# builders
|
||||
|
||||
/builder/alicloud/ @chhaj5236 @alexyueer
|
||||
/website/source/docs/builders/alicloud* @chhaj5236 @alexyueer
|
||||
/website/pages/docs/builders/alicloud* @chhaj5236 @alexyueer
|
||||
|
||||
/builder/azure/ @paulmey
|
||||
/website/source/docs/builders/azure* @paulmey
|
||||
/website/pages/docs/builders/azure* @paulmey
|
||||
|
||||
/builder/hyperv/ @taliesins
|
||||
/website/source/docs/builders/hyperv* @taliesins
|
||||
/website/pages/docs/builders/hyperv* @taliesins
|
||||
|
||||
/builder/jdcloud/ @XiaohanLiang @remrain
|
||||
/website/source/docs/builders/jdcloud* @XiaohanLiang @remrain
|
||||
/website/pages/docs/builders/jdcloud* @XiaohanLiang @remrain
|
||||
|
||||
/builder/linode/ @displague @ctreatma @stvnjacobs
|
||||
/website/source/docs/builders/linode* @displague @ctreatma @stvnjacobs
|
||||
/website/pages/docs/builders/linode* @displague @ctreatma @stvnjacobs
|
||||
|
||||
/builder/lxc/ @ChrisLundquist
|
||||
/website/source/docs/builders/lxc* @ChrisLundquist
|
||||
/website/pages/docs/builders/lxc* @ChrisLundquist
|
||||
|
||||
/builder/lxd/ @ChrisLundquist
|
||||
/website/source/docs/builders/lxd* @ChrisLundquist
|
||||
/website/pages/docs/builders/lxd* @ChrisLundquist
|
||||
|
||||
/builder/oneandone/ @jasmingacic
|
||||
/website/source/docs/builders/oneandone* @jasmingacic
|
||||
/website/pages/docs/builders/oneandone* @jasmingacic
|
||||
|
||||
/builder/oracle/ @prydie @owainlewis
|
||||
/website/source/docs/builders/oracle* @prydie @owainlewis
|
||||
/website/pages/docs/builders/oracle* @prydie @owainlewis
|
||||
|
||||
/builder/profitbricks/ @jasmingacic
|
||||
/website/source/docs/builders/profitbricks* @jasmingacic
|
||||
/website/pages/docs/builders/profitbricks* @jasmingacic
|
||||
|
||||
/builder/triton/ @sean-
|
||||
/website/source/docs/builders/triton* @sean-
|
||||
/website/pages/docs/builders/triton* @sean-
|
||||
|
||||
/builder/ncloud/ @YuSungDuk
|
||||
/website/source/docs/builders/ncloud* @YuSungDuk
|
||||
/website/pages/docs/builders/ncloud* @YuSungDuk
|
||||
|
||||
/builder/proxmox/ @carlpett
|
||||
/website/source/docs/builders/proxmox* @carlpett
|
||||
/website/pages/docs/builders/proxmox* @carlpett
|
||||
|
||||
/builder/scaleway/ @sieben @mvaude @jqueuniet @fflorens @brmzkw
|
||||
/website/source/docs/builders/scaleway* @sieben @mvaude @jqueuniet @fflorens @brmzkw
|
||||
/website/pages/docs/builders/scaleway* @sieben @mvaude @jqueuniet @fflorens @brmzkw
|
||||
|
||||
/builder/hcloud/ @LKaemmerling
|
||||
/website/source/docs/builders/hcloud* @LKaemmerling
|
||||
/website/pages/docs/builders/hcloud* @LKaemmerling
|
||||
|
||||
/builder/hyperone/ @m110 @gregorybrzeski @ad-m
|
||||
/website/source/docs/builders/hyperone* @m110 @gregorybrzeski @ad-m
|
||||
/website/pages/docs/builders/hyperone* @m110 @gregorybrzeski @ad-m
|
||||
|
||||
/builder/ucloud/ @shawnmssu
|
||||
/website/source/docs/builders/ucloud* @shawnmssu
|
||||
/website/pages/docs/builders/ucloud* @shawnmssu
|
||||
|
||||
/builder/yandex/ @GennadySpb @alexanderKhaustov @seukyaso
|
||||
/website/source/docs/builders/yandex* @GennadySpb @alexanderKhaustov @seukyaso
|
||||
/website/pages/docs/builders/yandex* @GennadySpb @alexanderKhaustov @seukyaso
|
||||
|
||||
/builder/osc/ @marinsalinas
|
||||
/website/source/docs/builders/osc* @marinsalinas
|
||||
/website/pages/docs/builders/osc* @marinsalinas
|
||||
|
||||
|
||||
# provisioners
|
||||
|
|
4
Makefile
4
Makefile
|
@ -108,7 +108,7 @@ mode-check: ## Check that only certain files are executable
|
|||
echo "Check passed."; \
|
||||
fi
|
||||
fmt-docs:
|
||||
@find ./website/source/docs -name "*.md" -exec pandoc --wrap auto --columns 79 --atx-headers -s -f "markdown_github+yaml_metadata_block" -t "markdown_github+yaml_metadata_block" {} -o {} \;
|
||||
@find ./website/pages/docs -name "*.md" -exec pandoc --wrap auto --columns 79 --atx-headers -s -f "markdown_github+yaml_metadata_block" -t "markdown_github+yaml_metadata_block" {} -o {} \;
|
||||
|
||||
# Install js-beautify with npm install -g js-beautify
|
||||
fmt-examples:
|
||||
|
@ -118,7 +118,7 @@ fmt-examples:
|
|||
# source files.
|
||||
generate: install-gen-deps ## Generate dynamically generated code
|
||||
@echo "==> removing autogenerated markdown..."
|
||||
@find website/source/ -type f | xargs grep -l '^<!-- Code generated' | xargs rm
|
||||
@find website/pages/ -type f | xargs grep -l '^<!-- Code generated' | xargs rm
|
||||
@echo "==> removing autogenerated code..."
|
||||
@find post-processor common helper template builder provisioner -type f | xargs grep -l '^// Code generated' | xargs rm
|
||||
go generate ./...
|
||||
|
|
|
@ -17,7 +17,7 @@ type AlicloudDiskDevice struct {
|
|||
// 128] English or Chinese characters, must begin with an
|
||||
// uppercase/lowercase letter or Chinese character. Can contain numbers,
|
||||
// ., _ and -. The disk name will appear on the console. It cannot
|
||||
// begin with http:// or https://.
|
||||
// begin with `http://` or `https://`.
|
||||
DiskName string `mapstructure:"disk_name" required:"false"`
|
||||
// Category of the system disk. Optional values
|
||||
// are:
|
||||
|
@ -35,7 +35,7 @@ type AlicloudDiskDevice struct {
|
|||
SnapshotId string `mapstructure:"disk_snapshot_id" required:"false"`
|
||||
// The value of disk description is blank by
|
||||
// default. [2, 256] characters. The disk description will appear on the
|
||||
// console. It cannot begin with http:// or https://.
|
||||
// console. It cannot begin with `http://` or `https://`.
|
||||
Description string `mapstructure:"disk_description" required:"false"`
|
||||
// Whether or not the disk is
|
||||
// released along with the instance:
|
||||
|
@ -139,14 +139,14 @@ type AlicloudImageConfig struct {
|
|||
// The name of the user-defined image, [2, 128]
|
||||
// English or Chinese characters. It must begin with an uppercase/lowercase
|
||||
// letter or a Chinese character, and may contain numbers, _ or -. It
|
||||
// cannot begin with http:// or https://.
|
||||
// cannot begin with `http://` or `https://`.
|
||||
AlicloudImageName string `mapstructure:"image_name" required:"true"`
|
||||
// The version number of the image, with a length
|
||||
// limit of 1 to 40 English characters.
|
||||
AlicloudImageVersion string `mapstructure:"image_version" required:"false"`
|
||||
// The description of the image, with a length
|
||||
// limit of 0 to 256 characters. Leaving it blank means null, which is the
|
||||
// default value. It cannot begin with http:// or https://.
|
||||
// default value. It cannot begin with `http://` or `https://`.
|
||||
AlicloudImageDescription string `mapstructure:"image_description" required:"false"`
|
||||
// The IDs of to-be-added Aliyun
|
||||
// accounts to which the image is shared. The number of accounts is 1 to 10.
|
||||
|
@ -158,7 +158,7 @@ type AlicloudImageConfig struct {
|
|||
// The name of the destination image,
|
||||
// [2, 128] English or Chinese characters. It must begin with an
|
||||
// uppercase/lowercase letter or a Chinese character, and may contain numbers,
|
||||
// _ or -. It cannot begin with http:// or https://.
|
||||
// _ or -. It cannot begin with `http://` or `https://`.
|
||||
AlicloudImageDestinationNames []string `mapstructure:"image_copy_names" required:"false"`
|
||||
// Whether or not to encrypt the target images, including those copied if image_copy_regions is specified. If this option
|
||||
// is set to true, a temporary image will be created from the provisioned
|
||||
|
@ -171,13 +171,13 @@ type AlicloudImageConfig struct {
|
|||
// images and then create the target images, otherwise, the creation will
|
||||
// fail. The default value is false. Check `image_name` and
|
||||
// `image_copy_names` options for names of target images. If
|
||||
// [-force](https://packer.io/docs/commands/build.html#force) option is
|
||||
// [-force](/docs/commands/build#force) option is
|
||||
// provided in `build` command, this option can be omitted and taken as
|
||||
// true.
|
||||
AlicloudImageForceDelete bool `mapstructure:"image_force_delete" required:"false"`
|
||||
// If this value is true, when delete the duplicated existing images, the
|
||||
// source snapshots of those images will be delete either. If
|
||||
// [-force](https://packer.io/docs/commands/build.html#force) option is
|
||||
// [-force](/docs/commands/build#force) option is
|
||||
// provided in `build` command, this option can be omitted and taken as
|
||||
// true.
|
||||
AlicloudImageForceDeleteSnapshots bool `mapstructure:"image_force_delete_snapshots" required:"false"`
|
||||
|
@ -194,7 +194,7 @@ type AlicloudImageConfig struct {
|
|||
AlicloudImageTags map[string]string `mapstructure:"tags" required:"false"`
|
||||
// Same as [`tags`](#tags) but defined as a singular repeatable block
|
||||
// containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
AlicloudImageTag hcl2template.NameValues `mapstructure:"tag" required:"false"`
|
||||
AlicloudDiskDevices `mapstructure:",squash"`
|
||||
|
|
|
@ -57,7 +57,7 @@ type RunConfig struct {
|
|||
// The security group name. The default value
|
||||
// is blank. [2, 128] English or Chinese characters, must begin with an
|
||||
// uppercase/lowercase letter or Chinese character. Can contain numbers, .,
|
||||
// _ or -. It cannot begin with http:// or https://.
|
||||
// _ or -. It cannot begin with `http://` or `https://`.
|
||||
SecurityGroupName string `mapstructure:"security_group_name" required:"false"`
|
||||
// User data to apply when launching the instance. Note
|
||||
// that you need to be careful about escaping characters due to the templates
|
||||
|
@ -73,8 +73,8 @@ type RunConfig struct {
|
|||
// The VPC name. The default value is blank. [2, 128]
|
||||
// English or Chinese characters, must begin with an uppercase/lowercase
|
||||
// letter or Chinese character. Can contain numbers, _ and -. The disk
|
||||
// description will appear on the console. Cannot begin with http:// or
|
||||
// https://.
|
||||
// description will appear on the console. Cannot begin with `http://` or
|
||||
// `https://`.
|
||||
VpcName string `mapstructure:"vpc_name" required:"false"`
|
||||
// Value options: 192.168.0.0/16 and
|
||||
// 172.16.0.0/16. When not specified, the default value is 172.16.0.0/16.
|
||||
|
|
|
@ -48,11 +48,11 @@ type Config struct {
|
|||
// in the Chroot Mounts section. Please read that section for more
|
||||
// information on how to use this.
|
||||
ChrootMounts [][]string `mapstructure:"chroot_mounts" required:"false"`
|
||||
// How to run shell commands. This defaults to {{.Command}}. This may be
|
||||
// How to run shell commands. This defaults to `{{.Command}}`. This may be
|
||||
// useful to set if you want to set environmental variables or perhaps run
|
||||
// it with sudo or so on. This is a configuration template where the
|
||||
// .Command variable is replaced with the command to be run. Defaults to
|
||||
// {{.Command}}.
|
||||
// `{{.Command}}`.
|
||||
CommandWrapper string `mapstructure:"command_wrapper" required:"false"`
|
||||
// Paths to files on the running EC2 instance that will be copied into the
|
||||
// chroot environment prior to provisioning. Defaults to /etc/resolv.conf
|
||||
|
@ -90,18 +90,18 @@ type Config struct {
|
|||
MountPartition string `mapstructure:"mount_partition" required:"false"`
|
||||
// The path where the volume will be mounted. This is where the chroot
|
||||
// environment will be. This defaults to
|
||||
// /mnt/packer-amazon-chroot-volumes/{{.Device}}. This is a configuration
|
||||
// `/mnt/packer-amazon-chroot-volumes/{{.Device}}`. This is a configuration
|
||||
// template where the .Device variable is replaced with the name of the
|
||||
// device where the volume is attached.
|
||||
MountPath string `mapstructure:"mount_path" required:"false"`
|
||||
// As pre_mount_commands, but the commands are executed after mounting the
|
||||
// root device and before the extra mount and copy steps. The device and
|
||||
// mount path are provided by {{.Device}} and {{.MountPath}}.
|
||||
// mount path are provided by `{{.Device}}` and `{{.MountPath}}`.
|
||||
PostMountCommands []string `mapstructure:"post_mount_commands" required:"false"`
|
||||
// A series of commands to execute after attaching the root volume and
|
||||
// before mounting the chroot. This is not required unless using
|
||||
// from_scratch. If so, this should include any partitioning and filesystem
|
||||
// creation commands. The path to the device is provided by {{.Device}}.
|
||||
// creation commands. The path to the device is provided by `{{.Device}}`.
|
||||
PreMountCommands []string `mapstructure:"pre_mount_commands" required:"false"`
|
||||
// The root device name. For example, xvda.
|
||||
RootDeviceName string `mapstructure:"root_device_name" required:"false"`
|
||||
|
@ -161,12 +161,12 @@ type Config struct {
|
|||
//filter, but will cause Packer to fail if the `source_ami` does not exist.
|
||||
SourceAmiFilter awscommon.AmiFilterOptions `mapstructure:"source_ami_filter" required:"false"`
|
||||
// Tags to apply to the volumes that are *launched*. This is a [template
|
||||
// engine](/docs/templates/engine.html), see [Build template
|
||||
// engine](/docs/templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
RootVolumeTags map[string]string `mapstructure:"root_volume_tags" required:"false"`
|
||||
// Same as [`root_volume_tags`](#root_volume_tags) but defined as a
|
||||
// singular block containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
RootVolumeTag hcl2template.NameValues `mapstructure:"root_volume_tag" required:"false"`
|
||||
// what architecture to use when registering the final AMI; valid options
|
||||
|
|
|
@ -44,7 +44,7 @@ func (v *VaultAWSEngineOptions) Empty() bool {
|
|||
// AccessConfig is for common configuration related to AWS access
|
||||
type AccessConfig struct {
|
||||
// The access key used to communicate with AWS. [Learn how to set this]
|
||||
// (/docs/builders/amazon.html#specifying-amazon-credentials). On EBS, this
|
||||
// (/docs/builders/amazon#specifying-amazon-credentials). On EBS, this
|
||||
// is not required if you are using `use_vault_aws_engine` for
|
||||
// authentication instead.
|
||||
AccessKey string `mapstructure:"access_key" required:"true"`
|
||||
|
@ -79,7 +79,7 @@ type AccessConfig struct {
|
|||
// When chroot building, this value is guessed from environment.
|
||||
RawRegion string `mapstructure:"region" required:"true"`
|
||||
// The secret key used to communicate with AWS. [Learn how to set
|
||||
// this](amazon.html#specifying-amazon-credentials). This is not required
|
||||
// this](/docs/builders/amazon#specifying-amazon-credentials). This is not required
|
||||
// if you are using `use_vault_aws_engine` for authentication instead.
|
||||
SecretKey string `mapstructure:"secret_key" required:"true"`
|
||||
// Set to true if you want to skip
|
||||
|
@ -95,7 +95,7 @@ type AccessConfig struct {
|
|||
// Get credentials from Hashicorp Vault's aws secrets engine. You must
|
||||
// already have created a role to use. For more information about
|
||||
// generating credentials via the Vault engine, see the [Vault
|
||||
// docs.](https://www.vaultproject.io/api/secret/aws/index.html#generate-credentials)
|
||||
// docs.](https://www.vaultproject.io/api/secret/aws#generate-credentials)
|
||||
// If you set this flag, you must also set the below options:
|
||||
// - `name` (string) - Required. Specifies the name of the role to generate
|
||||
// credentials against. This is part of the request URL.
|
||||
|
@ -190,7 +190,7 @@ func (c *AccessConfig) Session() (*session.Session, error) {
|
|||
|
||||
if isAWSErr(err, "NoCredentialProviders", "") {
|
||||
return nil, fmt.Errorf("No valid credential sources found for AWS Builder. " +
|
||||
"Please see https://www.packer.io/docs/builders/amazon.html#specifying-amazon-credentials " +
|
||||
"Please see https://www.packer.io/docs/builders/amazon#specifying-amazon-credentials " +
|
||||
"for more information on providing credentials for the AWS Builder.")
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ type AMIConfig struct {
|
|||
// The name of the resulting AMI that will appear when managing AMIs in the
|
||||
// AWS console or via APIs. This must be unique. To help make this unique,
|
||||
// use a function like timestamp (see [template
|
||||
// engine](../templates/engine.html) for more info).
|
||||
// engine](/docs/templates/engine) for more info).
|
||||
AMIName string `mapstructure:"ami_name" required:"true"`
|
||||
// The description to set for the resulting
|
||||
// AMI(s). By default this description is empty. This is a
|
||||
// [template engine](/docs/templates/engine.html), see [Build template
|
||||
// [template engine](/docs/templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
AMIDescription string `mapstructure:"ami_description" required:"false"`
|
||||
// The type of virtualization for the AMI
|
||||
|
@ -48,12 +48,12 @@ type AMIConfig struct {
|
|||
// validation of the ami_regions configuration option. Default false.
|
||||
AMISkipRegionValidation bool `mapstructure:"skip_region_validation" required:"false"`
|
||||
// Tags applied to the AMI. This is a
|
||||
// [template engine](/docs/templates/engine.html), see [Build template
|
||||
// [template engine](/docs/templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
AMITags map[string]string `mapstructure:"tags" required:"false"`
|
||||
// Same as [`tags`](#tags) but defined as a singular repeatable block
|
||||
// containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
AMITag hcl2template.NameValues `mapstructure:"tag" required:"false"`
|
||||
// Enable enhanced networking (ENA but not SriovNetSupport) on
|
||||
|
@ -119,12 +119,12 @@ type AMIConfig struct {
|
|||
AMISkipBuildRegion bool `mapstructure:"skip_save_build_region"`
|
||||
// Tags to apply to snapshot.
|
||||
// They will override AMI tags if already applied to snapshot. This is a
|
||||
// [template engine](../templates/engine.html), see [Build template
|
||||
// [template engine](/docs/templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false"`
|
||||
// Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular
|
||||
// repeatable block containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
SnapshotTag hcl2template.NameValues `mapstructure:"snapshot_tag" required:"false"`
|
||||
// A list of account IDs that have
|
||||
|
@ -210,7 +210,7 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
|
|||
if len(c.SnapshotUsers) > 0 {
|
||||
if len(c.AMIKmsKeyId) == 0 && len(c.AMIRegionKMSKeyIDs) == 0 && c.AMIEncryptBootVolume.True() {
|
||||
errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted "+
|
||||
"with default KMS key, see https://www.packer.io/docs/builders/amazon-ebs.html#region_kms_key_ids for more information"))
|
||||
"with default KMS key, see https://www.packer.io/docs/builders/amazon-ebs#region_kms_key_ids for more information"))
|
||||
}
|
||||
if len(c.AMIRegionKMSKeyIDs) > 0 {
|
||||
for _, kmsKey := range c.AMIRegionKMSKeyIDs {
|
||||
|
|
|
@ -90,7 +90,7 @@ type RunConfig struct {
|
|||
// *will not* stop the instance but will assume that you will send the stop
|
||||
// signal yourself through your final provisioner. You can do this with a
|
||||
// [windows-shell
|
||||
// provisioner](https://www.packer.io/docs/provisioners/windows-shell.html).
|
||||
// provisioner](/docs/provisioners/windows-shell).
|
||||
// Note that Packer will still wait for the instance to be stopped, and
|
||||
// failing to send the stop signal yourself, when you have set this flag to
|
||||
// `true`, will cause a timeout.
|
||||
|
@ -184,12 +184,12 @@ type RunConfig struct {
|
|||
// `security_group_ids` take precedence over this.
|
||||
SecurityGroupFilter SecurityGroupFilterOptions `mapstructure:"security_group_filter" required:"false"`
|
||||
// Tags to apply to the instance that is that is *launched* to create the
|
||||
// EBS volumes. This is a [template engine](/docs/templates/engine.html),
|
||||
// EBS volumes. This is a [template engine](/docs/templates/engine),
|
||||
// see [Build template data](#build-template-data) for more information.
|
||||
RunTags map[string]string `mapstructure:"run_tags" required:"false"`
|
||||
// Same as [`run_tags`](#run_tags) but defined as a singular repeatable
|
||||
// block containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
RunTag hcl2template.NameValues `mapstructure:"run_tag" required:"false"`
|
||||
// The ID (not the name) of the security
|
||||
|
@ -286,7 +286,7 @@ type RunConfig struct {
|
|||
SpotTags map[string]string `mapstructure:"spot_tags" required:"false"`
|
||||
// Same as [`spot_tags`](#spot_tags) but defined as a singular repeatable block
|
||||
// containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
SpotTag hcl2template.NameValues `mapstructure:"spot_tag" required:"false"`
|
||||
// Filters used to populate the `subnet_id` field.
|
||||
|
|
|
@ -9,7 +9,8 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/packer/command"
|
||||
amazonebsbuilder "github.com/hashicorp/packer/builder/amazon/ebs"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
|
||||
testshelper "github.com/hashicorp/packer/helper/tests"
|
||||
|
@ -18,7 +19,16 @@ import (
|
|||
type AmazonEBSAccTest struct{}
|
||||
|
||||
func (s *AmazonEBSAccTest) GetConfigs() (map[string]string, error) {
|
||||
filePath := filepath.Join("../../builder/amazon/ebs/acceptance/test-fixtures/", "amazon-ebs.txt")
|
||||
fixtures := map[string]string{
|
||||
"linux": "amazon-ebs.txt",
|
||||
"windows": "amazon-ebs_windows.txt",
|
||||
}
|
||||
|
||||
configs := make(map[string]string)
|
||||
|
||||
for distro, fixture := range fixtures {
|
||||
fileName := fixture
|
||||
filePath := filepath.Join("../../builder/amazon/ebs/acceptance/test-fixtures/", fileName)
|
||||
config, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Expected to find %s", filePath)
|
||||
|
@ -27,9 +37,13 @@ func (s *AmazonEBSAccTest) GetConfigs() (map[string]string, error) {
|
|||
|
||||
file, err := ioutil.ReadAll(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Uneble to read %s", filePath)
|
||||
return nil, fmt.Errorf("Unable to read %s", filePath)
|
||||
}
|
||||
return map[string]string{"linux": string(file)}, nil
|
||||
|
||||
configs[distro] = string(file)
|
||||
|
||||
}
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func (s *AmazonEBSAccTest) CleanUp() error {
|
||||
|
@ -42,6 +56,6 @@ func (s *AmazonEBSAccTest) CleanUp() error {
|
|||
|
||||
func (s *AmazonEBSAccTest) GetBuilderStore() packer.MapOfBuilder {
|
||||
return packer.MapOfBuilder{
|
||||
"amazon-ebs": func() (packer.Builder, error) { return command.Builders["amazon-ebs"], nil },
|
||||
"amazon-ebs": func() (packer.Builder, error) { return &amazonebsbuilder.Builder{}, nil },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"type": "amazon-ebs",
|
||||
"region": "us-east-1",
|
||||
"instance_type": "t2.micro",
|
||||
"source_ami_filter": {
|
||||
"filters": {
|
||||
"virtualization-type": "hvm",
|
||||
"name": "*Windows_Server-2012-R2*English-64Bit-Base*",
|
||||
"root-device-type": "ebs"
|
||||
},
|
||||
"most_recent": true,
|
||||
"owners": "amazon"
|
||||
},
|
||||
"ami_name": "packer-acc-test",
|
||||
"user_data_file": "../../builder/amazon/ebs/acceptance/test-fixtures/scripts/bootstrap_win.txt",
|
||||
"communicator": "winrm",
|
||||
"winrm_username": "Administrator",
|
||||
"winrm_password": "SuperS3cr3t!!!!",
|
||||
"force_deregister" : true,
|
||||
"tags": {
|
||||
"packer-test": "true"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<powershell>
|
||||
# Set administrator password
|
||||
net user Administrator SuperS3cr3t!!!!
|
||||
wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE
|
||||
|
||||
# First, make sure WinRM can't be connected to
|
||||
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=block
|
||||
|
||||
# Delete any existing WinRM listeners
|
||||
winrm delete winrm/config/listener?Address=*+Transport=HTTP 2>$Null
|
||||
winrm delete winrm/config/listener?Address=*+Transport=HTTPS 2>$Null
|
||||
|
||||
# Disable group policies which block basic authentication and unencrypted login
|
||||
|
||||
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WinRM\Client -Name AllowBasic -Value 1
|
||||
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WinRM\Client -Name AllowUnencryptedTraffic -Value 1
|
||||
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WinRM\Service -Name AllowBasic -Value 1
|
||||
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WinRM\Service -Name AllowUnencryptedTraffic -Value 1
|
||||
|
||||
|
||||
# Create a new WinRM listener and configure
|
||||
winrm create winrm/config/listener?Address=*+Transport=HTTP
|
||||
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="0"}'
|
||||
winrm set winrm/config '@{MaxTimeoutms="7200000"}'
|
||||
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
|
||||
winrm set winrm/config/service '@{MaxConcurrentOperationsPerUser="12000"}'
|
||||
winrm set winrm/config/service/auth '@{Basic="true"}'
|
||||
winrm set winrm/config/client/auth '@{Basic="true"}'
|
||||
|
||||
# Configure UAC to allow privilege elevation in remote shells
|
||||
$Key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
|
||||
$Setting = 'LocalAccountTokenFilterPolicy'
|
||||
Set-ItemProperty -Path $Key -Name $Setting -Value 1 -Force
|
||||
|
||||
# Configure and restart the WinRM Service; Enable the required firewall exception
|
||||
Stop-Service -Name WinRM
|
||||
Set-Service -Name WinRM -StartupType Automatic
|
||||
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new action=allow localip=any remoteip=any
|
||||
Start-Service -Name WinRM
|
||||
</powershell>
|
|
@ -52,7 +52,7 @@ type Config struct {
|
|||
// Tags to apply to the volumes that are *launched* to create the AMI.
|
||||
// These tags are *not* applied to the resulting AMI unless they're
|
||||
// duplicated in `tags`. This is a [template
|
||||
// engine](/docs/templates/engine.html), see [Build template
|
||||
// engine](/docs/templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
|
||||
// Relevant only to Windows guests: If you set this flag, we'll add clauses
|
||||
|
|
|
@ -58,7 +58,7 @@ type Config struct {
|
|||
// Tags to apply to the volumes that are *launched* to create the AMI.
|
||||
// These tags are *not* applied to the resulting AMI unless they're
|
||||
// duplicated in `tags`. This is a [template
|
||||
// engine](/docs/templates/engine.html), see [Build template
|
||||
// engine](/docs/templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
|
||||
// what architecture to use when registering the
|
||||
|
|
|
@ -12,12 +12,12 @@ import (
|
|||
type BlockDevice struct {
|
||||
awscommon.BlockDevice `mapstructure:",squash"`
|
||||
// Tags to apply to the volume. These are retained after the builder
|
||||
// completes. This is a [template engine](/docs/templates/engine.html), see
|
||||
// completes. This is a [template engine](/docs/templates/engine), see
|
||||
// [Build template data](#build-template-data) for more information.
|
||||
Tags map[string]string `mapstructure:"tags" required:"false"`
|
||||
// Same as [`tags`](#tags) but defined as a singular repeatable block
|
||||
// containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
Tag hcl2template.NameValues `mapstructure:"tag" required:"false"`
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ type Config struct {
|
|||
// create EBS Volumes. These tags will *not* appear in the tags of the
|
||||
// resulting EBS volumes unless they're duplicated under `tags` in the
|
||||
// `ebs_volumes` setting. This is a [template
|
||||
// engine](/docs/templates/engine.html), see [Build template
|
||||
// engine](/docs/templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
//
|
||||
// Note: The tags specified here will be *temporarily* applied to volumes
|
||||
|
@ -69,7 +69,7 @@ type Config struct {
|
|||
// Same as [`run_volume_tags`](#run_volume_tags) but defined as a singular
|
||||
// repeatable block containing a `name` and a `value` field. In HCL2 mode
|
||||
// the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
VolumeRunTag hcl2template.NameValues `mapstructure:"run_volume_tag"`
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ type Config struct {
|
|||
// exist and be writable.
|
||||
BundleDestination string `mapstructure:"bundle_destination" required:"false"`
|
||||
// The prefix for files created from bundling the root volume. By default
|
||||
// this is image-{{timestamp}}. The timestamp variable should be used to
|
||||
// this is `image-{{timestamp}}`. The timestamp variable should be used to
|
||||
// make sure this is unique, otherwise it can collide with other created
|
||||
// AMIs by Packer in your account.
|
||||
BundlePrefix string `mapstructure:"bundle_prefix" required:"false"`
|
||||
|
|
|
@ -247,7 +247,7 @@ type Config struct {
|
|||
AzureTags map[string]*string `mapstructure:"azure_tags" required:"false"`
|
||||
// Same as [`azure_tags`](#azure_tags) but defined as a singular repeatable block
|
||||
// containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
AzureTag hcl2template.NameValues `mapstructure:"azure_tag" required:"false"`
|
||||
// Resource group under which the final artifact will be stored.
|
||||
|
@ -399,6 +399,7 @@ type Config struct {
|
|||
tmpDeploymentName string
|
||||
tmpKeyVaultName string
|
||||
tmpOSDiskName string
|
||||
tmpDataDiskName string
|
||||
tmpSubnetName string
|
||||
tmpVirtualNetworkName string
|
||||
tmpNsgName string
|
||||
|
@ -655,6 +656,7 @@ func setRuntimeValues(c *Config) {
|
|||
c.tmpNicName = tempName.NicName
|
||||
c.tmpPublicIPAddressName = tempName.PublicIPAddressName
|
||||
c.tmpOSDiskName = tempName.OSDiskName
|
||||
c.tmpDataDiskName = tempName.DataDiskname
|
||||
c.tmpSubnetName = tempName.SubnetName
|
||||
c.tmpVirtualNetworkName = tempName.VirtualNetworkName
|
||||
c.tmpNsgName = tempName.NsgName
|
||||
|
|
|
@ -37,6 +37,7 @@ func GetVirtualMachineDeployment(config *Config) (*resources.Deployment, error)
|
|||
DnsNameForPublicIP: &template.TemplateParameter{Value: config.tmpComputeName},
|
||||
NicName: &template.TemplateParameter{Value: config.tmpNicName},
|
||||
OSDiskName: &template.TemplateParameter{Value: config.tmpOSDiskName},
|
||||
DataDiskName: &template.TemplateParameter{Value: config.tmpDataDiskName},
|
||||
PublicIPAddressName: &template.TemplateParameter{Value: config.tmpPublicIPAddressName},
|
||||
SubnetName: &template.TemplateParameter{Value: config.tmpSubnetName},
|
||||
StorageAccountBlobEndpoint: &template.TemplateParameter{Value: config.storageAccountBlobEndpoint},
|
||||
|
@ -96,7 +97,7 @@ func GetVirtualMachineDeployment(config *Config) (*resources.Deployment, error)
|
|||
|
||||
if len(config.AdditionalDiskSize) > 0 {
|
||||
isManaged := config.CustomManagedImageName != "" || (config.ManagedImageName != "" && config.ImagePublisher != "") || config.SharedGallery.Subscription != ""
|
||||
builder.SetAdditionalDisks(config.AdditionalDiskSize, isManaged, config.diskCachingType)
|
||||
builder.SetAdditionalDisks(config.AdditionalDiskSize, config.tmpDataDiskName, isManaged, config.diskCachingType)
|
||||
}
|
||||
|
||||
if config.customData != "" {
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -144,9 +147,9 @@
|
|||
"createOption": "Empty",
|
||||
"diskSizeGB": 32,
|
||||
"lun": 0,
|
||||
"name": "datadisk-1",
|
||||
"name": "[concat(parameters('dataDiskName'),'-1')]",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/datadisk-', '1','.vhd')]"
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),parameters('dataDiskName'), '-1','.vhd')]"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -147,7 +150,7 @@
|
|||
"managedDisk": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"name": "datadisk-1"
|
||||
"name": "[concat(parameters('dataDiskName'),'-1')]"
|
||||
}
|
||||
],
|
||||
"imageReference": {
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -15,6 +15,7 @@ type TempName struct {
|
|||
KeyVaultName string
|
||||
ResourceGroupName string
|
||||
OSDiskName string
|
||||
DataDiskname string
|
||||
NicName string
|
||||
SubnetName string
|
||||
PublicIPAddressName string
|
||||
|
@ -25,6 +26,7 @@ type TempName struct {
|
|||
func NewTempName(p string) *TempName {
|
||||
tempName := &TempName{}
|
||||
|
||||
|
||||
if p == "" {
|
||||
suffix := random.AlphaNumLower(10)
|
||||
tempName.ComputeName = fmt.Sprintf("pkrvm%s", suffix)
|
||||
|
|
|
@ -231,7 +231,7 @@ func (s *TemplateBuilder) SetOSDiskSizeGB(diskSizeGB int32) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *TemplateBuilder) SetAdditionalDisks(diskSizeGB []int32, isManaged bool, cachingType compute.CachingTypes) error {
|
||||
func (s *TemplateBuilder) SetAdditionalDisks(diskSizeGB []int32, dataDiskname string, isManaged bool, cachingType compute.CachingTypes) error {
|
||||
resource, err := s.getResourceByType(resourceVirtualMachine)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -243,7 +243,8 @@ func (s *TemplateBuilder) SetAdditionalDisks(diskSizeGB []int32, isManaged bool,
|
|||
for i, additionalSize := range diskSizeGB {
|
||||
dataDisks[i].DiskSizeGB = to.Int32Ptr(additionalSize)
|
||||
dataDisks[i].Lun = to.IntPtr(i)
|
||||
dataDisks[i].Name = to.StringPtr(fmt.Sprintf("datadisk-%d", i+1))
|
||||
// dataDisks[i].Name = to.StringPtr(fmt.Sprintf("%s-%d", dataDiskname, i+1))
|
||||
dataDisks[i].Name = to.StringPtr(fmt.Sprintf("[concat(parameters('dataDiskName'),'-%d')]", i+1))
|
||||
dataDisks[i].CreateOption = "Empty"
|
||||
dataDisks[i].Caching = cachingType
|
||||
if isManaged {
|
||||
|
@ -251,7 +252,7 @@ func (s *TemplateBuilder) SetAdditionalDisks(diskSizeGB []int32, isManaged bool,
|
|||
dataDisks[i].ManagedDisk = profile.OsDisk.ManagedDisk
|
||||
} else {
|
||||
dataDisks[i].Vhd = &compute.VirtualHardDisk{
|
||||
URI: to.StringPtr(fmt.Sprintf("[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/datadisk-', '%d','.vhd')]", i+1)),
|
||||
URI: to.StringPtr(fmt.Sprintf("[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),parameters('dataDiskName'), '-%d','.vhd')]", i+1)),
|
||||
}
|
||||
dataDisks[i].ManagedDisk = nil
|
||||
}
|
||||
|
@ -581,6 +582,9 @@ const BasicTemplate = `{
|
|||
},
|
||||
"vmName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -161,7 +164,7 @@
|
|||
"managedDisk": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"name": "datadisk-1"
|
||||
"name": "[concat(parameters('dataDiskName'),'-1')]"
|
||||
},
|
||||
{
|
||||
"caching": "ReadWrite",
|
||||
|
@ -171,7 +174,7 @@
|
|||
"managedDisk": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"name": "datadisk-2"
|
||||
"name": "[concat(parameters('dataDiskName'),'-2')]"
|
||||
}
|
||||
],
|
||||
"imageReference": {
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -158,9 +161,9 @@
|
|||
"createOption": "Empty",
|
||||
"diskSizeGB": 32,
|
||||
"lun": 0,
|
||||
"name": "datadisk-1",
|
||||
"name": "[concat(parameters('dataDiskName'),'-1')]",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/datadisk-', '1','.vhd')]"
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),parameters('dataDiskName'), '-1','.vhd')]"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -168,9 +171,9 @@
|
|||
"createOption": "Empty",
|
||||
"diskSizeGB": 64,
|
||||
"lun": 1,
|
||||
"name": "datadisk-2",
|
||||
"name": "[concat(parameters('dataDiskName'),'-2')]",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/datadisk-', '2','.vhd')]"
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),parameters('dataDiskName'), '-2','.vhd')]"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dataDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
@ -138,7 +138,7 @@ func TestBuildWindows01(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = testSubject.SetAdditionalDisks([]int32{32, 64}, true, compute.CachingTypesReadWrite)
|
||||
err = testSubject.SetAdditionalDisks([]int32{32, 64}, "datadisk", true, compute.CachingTypesReadWrite)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ func TestBuildWindows02(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = testSubject.SetAdditionalDisks([]int32{32, 64}, false, compute.CachingTypesReadWrite)
|
||||
err = testSubject.SetAdditionalDisks([]int32{32, 64}, "datadisk", false, compute.CachingTypesReadWrite)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ type TemplateParameters struct {
|
|||
ObjectId *TemplateParameter `json:"objectId,omitempty"`
|
||||
NicName *TemplateParameter `json:"nicName,omitempty"`
|
||||
OSDiskName *TemplateParameter `json:"osDiskName,omitempty"`
|
||||
DataDiskName *TemplateParameter `json:"dataDiskName,omitempty"`
|
||||
PublicIPAddressName *TemplateParameter `json:"publicIPAddressName,omitempty"`
|
||||
StorageAccountBlobEndpoint *TemplateParameter `json:"storageAccountBlobEndpoint,omitempty"`
|
||||
SubnetName *TemplateParameter `json:"subnetName,omitempty"`
|
||||
|
|
|
@ -103,6 +103,7 @@ type Config struct {
|
|||
// as the source for this build. *VHD targets are incompatible with this
|
||||
// build type* - the target must be a *Managed Image*.
|
||||
//
|
||||
// ```json
|
||||
// "shared_image_gallery": {
|
||||
// "subscription": "00000000-0000-0000-0000-00000000000",
|
||||
// "resource_group": "ResourceGroup",
|
||||
|
@ -112,14 +113,14 @@ type Config struct {
|
|||
// }
|
||||
// "managed_image_name": "TargetImageName",
|
||||
// "managed_image_resource_group_name": "TargetResourceGroup"
|
||||
// ```
|
||||
SharedGallery SharedImageGallery `mapstructure:"shared_image_gallery"`
|
||||
|
||||
// The name of the Shared Image Gallery under which the managed image will be published as Shared Gallery Image version.
|
||||
//
|
||||
// Following is an example.
|
||||
//
|
||||
// <!-- -->
|
||||
//
|
||||
// ```json
|
||||
// "shared_image_gallery_destination": {
|
||||
// "resource_group": "ResourceGroup",
|
||||
// "gallery_name": "GalleryName",
|
||||
|
@ -129,6 +130,7 @@ type Config struct {
|
|||
// }
|
||||
// "managed_image_name": "TargetImageName",
|
||||
// "managed_image_resource_group_name": "TargetResourceGroup"
|
||||
// ```
|
||||
SharedGalleryDestination SharedImageGalleryDestination `mapstructure:"shared_image_gallery_destination"`
|
||||
|
||||
// How long to wait for an image to be published to the shared image
|
||||
|
|
|
@ -114,7 +114,7 @@ type Config struct {
|
|||
SourceTemplate string `mapstructure:"source_template" required:"true"`
|
||||
// The name of the temporary SSH key pair
|
||||
// to generate. By default, Packer generates a name that looks like
|
||||
// packer_<UUID>, where <UUID> is a 36 character unique identifier.
|
||||
// `packer_<UUID>`, where `<UUID>` is a 36 character unique identifier.
|
||||
TemporaryKeypairName string `mapstructure:"temporary_keypair_name" required:"false"`
|
||||
// Set to true to indicate that the
|
||||
// provisioners should connect to the local IP address of the instance.
|
||||
|
@ -134,7 +134,7 @@ type Config struct {
|
|||
// created.
|
||||
Zone string `mapstructure:"zone" required:"true"`
|
||||
// The name of the new template. Defaults to
|
||||
// "packer-{{timestamp}}" where timestamp will be the current time.
|
||||
// `packer-{{timestamp}}` where timestamp will be the current time.
|
||||
TemplateName string `mapstructure:"template_name" required:"false"`
|
||||
// The display text of the new template.
|
||||
// Defaults to the template_name.
|
||||
|
|
|
@ -55,7 +55,7 @@ type Config struct {
|
|||
// created. This defaults to false, or not enabled.
|
||||
IPv6 bool `mapstructure:"ipv6" required:"false"`
|
||||
// The name of the resulting snapshot that will
|
||||
// appear in your account. Defaults to "packer-{{timestamp}}" (see
|
||||
// appear in your account. Defaults to `packer-{{timestamp}}` (see
|
||||
// configuration templates for more info).
|
||||
SnapshotName string `mapstructure:"snapshot_name" required:"false"`
|
||||
// The regions of the resulting
|
||||
|
|
|
@ -36,12 +36,12 @@ type Config struct {
|
|||
Commit bool `mapstructure:"commit" required:"true"`
|
||||
|
||||
// The directory inside container to mount temp directory from host server
|
||||
// for work [file provisioner](/docs/provisioners/file.html). This defaults
|
||||
// for work [file provisioner](/docs/provisioners/file). This defaults
|
||||
// to c:/packer-files on windows and /packer-files on other systems.
|
||||
ContainerDir string `mapstructure:"container_dir" required:"false"`
|
||||
// Throw away the container when the build is complete. This is useful for
|
||||
// the [artifice
|
||||
// post-processor](https://www.packer.io/docs/post-processors/artifice.html).
|
||||
// post-processor](/docs/post-processors/artifice).
|
||||
Discard bool `mapstructure:"discard" required:"true"`
|
||||
// Username (UID) to run remote commands with. You can also set the group
|
||||
// name/ID if you want: (UID or UID:GID). You may need this if you get
|
||||
|
@ -63,10 +63,10 @@ type Config struct {
|
|||
// used. This defaults to true if not set.
|
||||
Pull bool `mapstructure:"pull" required:"false"`
|
||||
// An array of arguments to pass to docker run in order to run the
|
||||
// container. By default this is set to ["-d", "-i", "-t",
|
||||
// "--entrypoint=/bin/sh", "--", "{{.Image}}"] if you are using a linux
|
||||
// container, and ["-d", "-i", "-t", "--entrypoint=powershell", "--",
|
||||
// "{{.Image}}"] if you are running a windows container. {{.Image}} is a
|
||||
// container. By default this is set to `["-d", "-i", "-t",
|
||||
// "--entrypoint=/bin/sh", "--", "{{.Image}}"]` if you are using a linux
|
||||
// container, and `["-d", "-i", "-t", "--entrypoint=powershell", "--",
|
||||
// "{{.Image}}"]` if you are running a windows container. `{{.Image}}` is a
|
||||
// template variable that corresponds to the image template option. Passing
|
||||
// the entrypoint option this way will make it the default entrypoint of
|
||||
// the resulting image, so running docker run -it --rm will start the
|
||||
|
|
|
@ -58,7 +58,7 @@ type Config struct {
|
|||
// Defaults to pd-standard.
|
||||
DiskType string `mapstructure:"disk_type" required:"false"`
|
||||
// The unique name of the resulting image. Defaults to
|
||||
// "packer-{{timestamp}}".
|
||||
// `packer-{{timestamp}}`.
|
||||
ImageName string `mapstructure:"image_name" required:"false"`
|
||||
// The description of the resulting image.
|
||||
ImageDescription string `mapstructure:"image_description" required:"false"`
|
||||
|
@ -84,7 +84,7 @@ type Config struct {
|
|||
// Licenses to apply to the created image.
|
||||
ImageLicenses []string `mapstructure:"image_licenses" required:"false"`
|
||||
// A name to give the launched instance. Beware that this must be unique.
|
||||
// Defaults to "packer-{{uuid}}".
|
||||
// Defaults to `packer-{{uuid}}`.
|
||||
InstanceName string `mapstructure:"instance_name" required:"false"`
|
||||
// Key/value pair labels to apply to the launched instance.
|
||||
Labels map[string]string `mapstructure:"labels" required:"false"`
|
||||
|
@ -172,7 +172,7 @@ type Config struct {
|
|||
// Google's cloud. The value should be the path of the token generator
|
||||
// within vault.
|
||||
// For information on how to configure your Vault + GCP engine to produce
|
||||
// Oauth tokens, see https://www.vaultproject.io/docs/auth/gcp.html
|
||||
// Oauth tokens, see https://www.vaultproject.io/docs/auth/gcp
|
||||
// You must have the environment variables VAULT_ADDR and VAULT_TOKEN set,
|
||||
// along with any other relevant variables for accessing your vault
|
||||
// instance. For more information, see the Vault docs:
|
||||
|
|
|
@ -56,7 +56,7 @@ type Config struct {
|
|||
// ID or name of the image to launch server from.
|
||||
SourceImage string `mapstructure:"source_image" required:"true"`
|
||||
// The name of the resulting image. Defaults to
|
||||
// "packer-{{timestamp}}"
|
||||
// `packer-{{timestamp}}`
|
||||
// (see configuration templates for more info).
|
||||
ImageName string `mapstructure:"image_name" required:"false"`
|
||||
// The description of the resulting image.
|
||||
|
@ -65,7 +65,7 @@ type Config struct {
|
|||
ImageTags map[string]string `mapstructure:"image_tags" required:"false"`
|
||||
// Same as [`image_tags`](#image_tags) but defined as a singular repeatable
|
||||
// block containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
ImageTag hcl2template.NameValues `mapstructure:"image_tag" required:"false"`
|
||||
// The service of the resulting image.
|
||||
|
@ -79,7 +79,7 @@ type Config struct {
|
|||
VmTags map[string]string `mapstructure:"vm_tags" required:"false"`
|
||||
// Same as [`vm_tags`](#vm_tags) but defined as a singular repeatable block
|
||||
// containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
VmTag hcl2template.NameValues `mapstructure:"vm_tag" required:"false"`
|
||||
// The name of the created disk.
|
||||
|
@ -107,11 +107,11 @@ type Config struct {
|
|||
ChrootMountPath string `mapstructure:"chroot_mount_path"`
|
||||
ChrootMounts [][]string `mapstructure:"chroot_mounts"`
|
||||
ChrootCopyFiles []string `mapstructure:"chroot_copy_files"`
|
||||
// How to run shell commands. This defaults to {{.Command}}. This may be
|
||||
// How to run shell commands. This defaults to `{{.Command}}`. This may be
|
||||
// useful to set if you want to set environmental variables or perhaps run
|
||||
// it with sudo or so on. This is a configuration template where the
|
||||
// .Command variable is replaced with the command to be run. Defaults to
|
||||
// {{.Command}}.
|
||||
// `{{.Command}}`.
|
||||
ChrootCommandWrapper string `mapstructure:"chroot_command_wrapper"`
|
||||
|
||||
MountOptions []string `mapstructure:"mount_options"`
|
||||
|
@ -119,11 +119,11 @@ type Config struct {
|
|||
// A series of commands to execute after attaching the root volume and
|
||||
// before mounting the chroot. This is not required unless using
|
||||
// from_scratch. If so, this should include any partitioning and filesystem
|
||||
// creation commands. The path to the device is provided by {{.Device}}.
|
||||
// creation commands. The path to the device is provided by `{{.Device}}`.
|
||||
PreMountCommands []string `mapstructure:"pre_mount_commands"`
|
||||
// As pre_mount_commands, but the commands are executed after mounting the
|
||||
// root device and before the extra mount and copy steps. The device and
|
||||
// mount path are provided by {{.Device}} and {{.MountPath}}.
|
||||
// mount path are provided by `{{.Device}}` and `{{.MountPath}}`.
|
||||
PostMountCommands []string `mapstructure:"post_mount_commands"`
|
||||
// List of SSH keys by name or id to be added
|
||||
// to the server on launch.
|
||||
|
|
|
@ -20,11 +20,11 @@ type Config struct {
|
|||
// The path to the lxc configuration file.
|
||||
ConfigFile string `mapstructure:"config_file" required:"true"`
|
||||
// The directory in which to save the exported
|
||||
// tar.gz. Defaults to output-<BuildName> in the current directory.
|
||||
// tar.gz. Defaults to `output-<BuildName>` in the current directory.
|
||||
OutputDir string `mapstructure:"output_directory" required:"false"`
|
||||
// The name of the LXC container. Usually stored
|
||||
// in /var/lib/lxc/containers/<container_name>. Defaults to
|
||||
// packer-<BuildName>.
|
||||
// in `/var/lib/lxc/containers/<container_name>`. Defaults to
|
||||
// `packer-<BuildName>`.
|
||||
ContainerName string `mapstructure:"container_name" required:"false"`
|
||||
// Allows you to specify a wrapper command, such
|
||||
// as ssh so you can execute packer builds on a remote host. Defaults to
|
||||
|
@ -53,7 +53,7 @@ type Config struct {
|
|||
Name string `mapstructure:"template_name" required:"true"`
|
||||
// Options to pass to the given
|
||||
// lxc-template command, usually located in
|
||||
// /usr/share/lxc/templates/lxc-<template_name>. Note: This gets passed as
|
||||
// `/usr/share/lxc/templates/lxc-<template_name>`. Note: This gets passed as
|
||||
// ARGV to the template command. Ensure you have an array of strings, as a
|
||||
// single string with spaces probably won't work. Defaults to [].
|
||||
Parameters []string `mapstructure:"template_parameters" required:"false"`
|
||||
|
|
|
@ -20,7 +20,7 @@ type Config struct {
|
|||
OutputImage string `mapstructure:"output_image" required:"false"`
|
||||
ContainerName string `mapstructure:"container_name"`
|
||||
// Lets you prefix all builder commands, such as
|
||||
// with ssh for a remote build host. Defaults to "{{.Command}}"; i.e. no
|
||||
// with ssh for a remote build host. Defaults to `{{.Command}}`; i.e. no
|
||||
// wrapper.
|
||||
CommandWrapper string `mapstructure:"command_wrapper" required:"false"`
|
||||
// The source image to use when creating the build
|
||||
|
|
|
@ -66,13 +66,9 @@ type RunConfig struct {
|
|||
// following are valid:
|
||||
//
|
||||
// - name (string)
|
||||
//
|
||||
// - owner (string)
|
||||
//
|
||||
// - tags (array of strings)
|
||||
//
|
||||
// - visibility (string)
|
||||
//
|
||||
// - properties (map of strings to strings) (fields that can be set
|
||||
// with `openstack image set --property key=value`)
|
||||
//
|
||||
|
|
|
@ -29,7 +29,7 @@ type ToolsConfig struct {
|
|||
// is "upload". This is a configuration
|
||||
// template that has a single
|
||||
// valid variable: Flavor, which will be the value of
|
||||
// parallels_tools_flavor. By default this is "prl-tools-{{.Flavor}}.iso"
|
||||
// parallels_tools_flavor. By default this is `prl-tools-{{.Flavor}}.iso`
|
||||
// which should upload into the login directory of the user.
|
||||
ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path" required:"false"`
|
||||
// The method by which Parallels Tools are
|
||||
|
|
|
@ -65,7 +65,7 @@ type Config struct {
|
|||
HardDriveInterface string `mapstructure:"hard_drive_interface" required:"false"`
|
||||
// A list of which interfaces on the
|
||||
// host should be searched for a IP address. The first IP address found on one
|
||||
// of these will be used as {{ .HTTPIP }} in the boot_command. Defaults to
|
||||
// of these will be used as `{{ .HTTPIP }}` in the boot_command. Defaults to
|
||||
// ["en0", "en1", "en2", "en3", "en4", "en5", "en6", "en7", "en8", "en9",
|
||||
// "ppp0", "ppp1", "ppp2"].
|
||||
HostInterfaces []string `mapstructure:"host_interfaces" required:"false"`
|
||||
|
|
|
@ -86,7 +86,7 @@ type TencentCloudRunConfig struct {
|
|||
RunTags map[string]string `mapstructure:"run_tags" required:"false"`
|
||||
// Same as [`run_tags`](#run_tags) but defined as a singular repeatable
|
||||
// block containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
RunTag hcl2template.NameValues `mapstructure:"run_tag" required:"false"`
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ type SourceMachineConfig struct {
|
|||
MachineTags map[string]string `mapstructure:"source_machine_tags" required:"false"`
|
||||
// Same as [`source_machine_tags`](#source_machine_tags) but defined as a
|
||||
// singular block containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
MachineTag hcl2template.NameValues `mapstructure:"source_machine_tag" required:"false"`
|
||||
// Whether or not the firewall
|
||||
|
|
|
@ -39,7 +39,7 @@ type TargetImageConfig struct {
|
|||
ImageTags map[string]string `mapstructure:"image_tags" required:"false"`
|
||||
// Same as [`image_tags`](#image_tags) but defined as a singular repeatable
|
||||
// block containing a `name` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](https://packer.io/docs/configuration/from-1.5/expressions.html#dynamic-blocks)
|
||||
// [`dynamic_block`](/docs/configuration/from-1.5/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
ImageTag hcl2template.NameValues `mapstructure:"image_tag" required:"false"`
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ type Config struct {
|
|||
BoxVersion string `mapstructure:"box_version" required:"false"`
|
||||
// a path to a golang template for a vagrantfile. Our default template can
|
||||
// be found here. The template variables available to you are
|
||||
// {{ .BoxName }}, {{ .SyncedFolder }}, and {{.InsertKey}}, which
|
||||
// `{{ .BoxName }}`, `{{ .SyncedFolder }}`, and `{{.InsertKey}}`, which
|
||||
// correspond to the Packer options box_name, synced_folder, and insert_key.
|
||||
Template string `mapstructure:"template" required:"false"`
|
||||
|
||||
|
|
|
@ -39,8 +39,7 @@ type ExportConfig struct {
|
|||
// packer call like this (shell `>` continuation character snipped for easier
|
||||
// copy & paste):
|
||||
//
|
||||
// ``` {.shell}
|
||||
//
|
||||
// ``` shell
|
||||
// vm_description='some
|
||||
// multiline
|
||||
// description'
|
||||
|
|
|
@ -14,7 +14,7 @@ type VBoxManageConfig struct {
|
|||
// array of strings, where each string represents a single argument on the
|
||||
// command-line to `VBoxManage` (but excluding `VBoxManage` itself). Each
|
||||
// arg is treated as a [configuration
|
||||
// template](/docs/templates/engine.html), where the `Name` variable is
|
||||
// template](/docs/templates/engine), where the `Name` variable is
|
||||
// replaced with the VM name. More details on how to use `VBoxManage` are
|
||||
// below.
|
||||
VBoxManage [][]string `mapstructure:"vboxmanage" required:"false"`
|
||||
|
|
|
@ -9,7 +9,8 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/packer/command"
|
||||
"github.com/hashicorp/packer/builder/virtualbox/iso"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
|
||||
testshelper "github.com/hashicorp/packer/helper/tests"
|
||||
|
@ -40,6 +41,6 @@ func (v *VirtualBoxISOAccTest) CleanUp() error {
|
|||
|
||||
func (v *VirtualBoxISOAccTest) GetBuilderStore() packer.MapOfBuilder {
|
||||
return packer.MapOfBuilder{
|
||||
"virtualbox-iso": func() (packer.Builder, error) { return command.Builders["virtualbox-iso"], nil },
|
||||
"virtualbox-iso": func() (packer.Builder, error) { return &iso.Builder{}, nil },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ type ExportConfig struct {
|
|||
// argument. Currently, exporting the build VM (with ovftool) is only
|
||||
// supported when building on ESXi e.g. when `remote_type` is set to
|
||||
// `esx5`. See the [Building on a Remote vSphere
|
||||
// Hypervisor](/docs/builders/vmware-iso.html#building-on-a-remote-vsphere-hypervisor)
|
||||
// Hypervisor](/docs/builders/vmware-iso#building-on-a-remote-vsphere-hypervisor)
|
||||
// section below for more info.
|
||||
OVFToolOptions []string `mapstructure:"ovftool_options" required:"false"`
|
||||
// Defaults to `false`. When enabled, Packer will not export the VM. Useful
|
||||
|
@ -30,7 +30,7 @@ type ExportConfig struct {
|
|||
// VM. Currently, exporting the build VM is only supported when building on
|
||||
// ESXi e.g. when `remote_type` is set to `esx5`. See the [Building on a
|
||||
// Remote vSphere
|
||||
// Hypervisor](/docs/builders/vmware-iso.html#building-on-a-remote-vsphere-hypervisor)
|
||||
// Hypervisor](/docs/builders/vmware-iso#building-on-a-remote-vsphere-hypervisor)
|
||||
// section below for more info.
|
||||
SkipExport bool `mapstructure:"skip_export" required:"false"`
|
||||
// Set this to true if you would like to keep
|
||||
|
|
|
@ -13,7 +13,7 @@ type ToolsConfig struct {
|
|||
ToolsUploadFlavor string `mapstructure:"tools_upload_flavor" required:"false"`
|
||||
// The path in the VM to upload the VMware tools. This only takes effect if
|
||||
// `tools_upload_flavor` is non-empty. This is a [configuration
|
||||
// template](/docs/templates/engine.html) that has a single valid variable:
|
||||
// template](/docs/templates/engine) that has a single valid variable:
|
||||
// `Flavor`, which will be the value of `tools_upload_flavor`. By default
|
||||
// the upload path is set to `{{.Flavor}}.iso`. This setting is not used
|
||||
// when `remote_type` is `esx5`.
|
||||
|
|
|
@ -107,7 +107,7 @@ type Config struct {
|
|||
VMName string `mapstructure:"vm_name" required:"false"`
|
||||
|
||||
VMXDiskTemplatePath string `mapstructure:"vmx_disk_template_path"`
|
||||
// Path to a [configuration template](/docs/templates/engine.html) that
|
||||
// Path to a [configuration template](/docs/templates/engine) that
|
||||
// defines the contents of the virtual machine VMX file for VMware. The
|
||||
// engine has access to the template variables `{{ .DiskNumber }}` and
|
||||
// `{{ .DiskName }}`.
|
||||
|
|
|
@ -42,7 +42,7 @@ import (
|
|||
// ```
|
||||
// The above configuration would create the following files:
|
||||
//
|
||||
// ```
|
||||
// ```text
|
||||
// ./output_vsphere/example-ubuntu-disk-0.vmdk
|
||||
// ./output_vsphere/example-ubuntu.mf
|
||||
// ./output_vsphere/example-ubuntu.ovf
|
||||
|
|
|
@ -64,18 +64,18 @@ func main() {
|
|||
header := Struct{
|
||||
SourcePath: sourcePath,
|
||||
Name: typeSpec.Name.Name,
|
||||
Filename: "_" + typeSpec.Name.Name + ".html.md",
|
||||
Filename: typeSpec.Name.Name + ".mdx",
|
||||
Header: typeDecl.Doc.Text(),
|
||||
}
|
||||
required := Struct{
|
||||
SourcePath: sourcePath,
|
||||
Name: typeSpec.Name.Name,
|
||||
Filename: "_" + typeSpec.Name.Name + "-required.html.md",
|
||||
Filename: typeSpec.Name.Name + "-required.mdx",
|
||||
}
|
||||
notRequired := Struct{
|
||||
SourcePath: sourcePath,
|
||||
Name: typeSpec.Name.Name,
|
||||
Filename: "_" + typeSpec.Name.Name + "-not-required.html.md",
|
||||
Filename: typeSpec.Name.Name + "-not-required.mdx",
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
|
@ -133,7 +133,7 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
dir := filepath.Join(packerDir, "website", "source", "partials", builderName)
|
||||
dir := filepath.Join(packerDir, "website", "pages", "partials", builderName)
|
||||
os.MkdirAll(dir, 0755)
|
||||
|
||||
for _, str := range []Struct{header, required, notRequired} {
|
||||
|
|
|
@ -50,7 +50,7 @@ func (c *VersionCommand) Run(args []string) int {
|
|||
if info.Outdated {
|
||||
c.Ui.Say(fmt.Sprintf(
|
||||
"\nYour version of Packer is out of date! The latest version\n"+
|
||||
"is %s. You can update by downloading from www.packer.io/downloads.html",
|
||||
"is %s. You can update by downloading from www.packer.io/downloads",
|
||||
info.Latest))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ import (
|
|||
// ]
|
||||
// ```
|
||||
// For more examples of various boot commands, see the sample projects from our
|
||||
// [community templates page](/community-tools.html#templates).
|
||||
// [community templates page](/community-tools#templates).
|
||||
type BootConfig struct {
|
||||
// Time to wait after sending a group of key pressses. The value of this
|
||||
// should be a duration. Examples are `5s` and `1m30s` which will cause
|
||||
|
@ -117,7 +117,8 @@ type BootConfig struct {
|
|||
// the `boot_command`. The value of this should be a duration. Examples are
|
||||
// `5s` and `1m30s` which will cause Packer to wait five seconds and one
|
||||
// minute 30 seconds, respectively. If this isn't specified, the default is
|
||||
// `10s` or 10 seconds.
|
||||
// `10s` or 10 seconds. To set boot_wait to 0s, use a negative number, such
|
||||
// as "-1s"
|
||||
BootWait time.Duration `mapstructure:"boot_wait"`
|
||||
// This is an array of commands to type when the virtual machine is first
|
||||
// booted. The goal of these commands should be to type just enough to
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
// is attached as the first floppy device. The summary size of the listed files
|
||||
// must not exceed 1.44 MB. The supported ways to move large files into the OS
|
||||
// are using `http_directory` or [the file
|
||||
// provisioner](https://www.packer.io/docs/provisioners/file.html).
|
||||
// provisioner](/docs/provisioners/file).
|
||||
type FloppyConfig struct {
|
||||
// A list of files to place onto a floppy disk that is attached when the VM
|
||||
// is booted. Currently, no support exists for creating sub-directories on
|
||||
|
|
|
@ -894,7 +894,7 @@ func scpUploadFile(dst string, src io.Reader, w io.Writer, r *bufio.Reader, fi *
|
|||
if _, err := io.Copy(tf, src); err != nil {
|
||||
return fmt.Errorf("Error copying input data into local temporary "+
|
||||
"file. Check that TEMPDIR has enough space. Please see "+
|
||||
"https://www.packer.io/docs/other/environment-variables.html#tmpdir"+
|
||||
"https://www.packer.io/docs/other/environment-variables#tmpdir"+
|
||||
"for more info. Error: %s", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ func (v *Variable) Value() (cty.Value, *hcl.Diagnostic) {
|
|||
Severity: hcl.DiagError,
|
||||
Summary: fmt.Sprintf("Unset variable %q", v.Name),
|
||||
Detail: "A used variable must be set or have a default value; see " +
|
||||
"https://packer.io/docs/configuration/from-1.5/syntax.html for " +
|
||||
"https://packer.io/docs/configuration/from-1.5/syntax for " +
|
||||
"details.",
|
||||
Context: v.Range.Ptr(),
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ type WinRM struct {
|
|||
//
|
||||
// NOTE: If using an Amazon EBS builder, you can specify the interface
|
||||
// WinRM connects to via
|
||||
// [`ssh_interface`](https://www.packer.io/docs/builders/amazon-ebs.html#ssh_interface)
|
||||
// [`ssh_interface`](/docs/builders/amazon-ebs#ssh_interface)
|
||||
WinRMHost string `mapstructure:"winrm_host"`
|
||||
// The WinRM port to connect to. This defaults to `5985` for plain
|
||||
// unencrypted connection and `5986` for SSL when `winrm_use_ssl` is set to
|
||||
|
|
|
@ -3,13 +3,14 @@ package acc
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/hashicorp/packer/helper/tests"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
testshelper "github.com/hashicorp/packer/helper/tests"
|
||||
|
||||
amazonEBS "github.com/hashicorp/packer/builder/amazon/ebs/acceptance"
|
||||
virtualboxISO "github.com/hashicorp/packer/builder/virtualbox/iso/acceptance"
|
||||
"github.com/hashicorp/packer/command"
|
||||
|
@ -68,6 +69,26 @@ func TestProvisionersAgainstBuilders(provisionerAcc ProvisionerAcceptance, t *te
|
|||
}
|
||||
}
|
||||
|
||||
// TestProvisionersPreCheck checks if the Provisioner with name is set in ACC_TEST_PROVISIONERS environment variable
|
||||
func TestProvisionersPreCheck(name string, t *testing.T) {
|
||||
p := os.Getenv("ACC_TEST_PROVISIONERS")
|
||||
|
||||
if p == "all" {
|
||||
return
|
||||
}
|
||||
|
||||
provisioners := strings.Split(p, ",")
|
||||
for _, provisioner := range provisioners {
|
||||
if provisioner == name {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("Provisioner %q not defined in ACC_TEST_PROVISIONERS", name)
|
||||
t.Skip(msg)
|
||||
|
||||
}
|
||||
|
||||
func checkBuilders(t *testing.T) []string {
|
||||
b := os.Getenv("ACC_TEST_BUILDERS")
|
||||
// validate if we want to run provisioners acc tests
|
||||
|
|
|
@ -4,6 +4,7 @@ package powershell
|
|||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ExecutionPolicy setting to run the command(s).
|
||||
|
@ -27,5 +28,14 @@ func StringToExecutionPolicyHook(f reflect.Kind, t reflect.Kind, data interface{
|
|||
}
|
||||
|
||||
raw := data.(string)
|
||||
// It's possible that the thing being read is not supposed to be an
|
||||
// execution policy; if the string provided is actally an int, just return
|
||||
// the int.
|
||||
i, err := strconv.Atoi(raw)
|
||||
if err == nil {
|
||||
return i, nil
|
||||
}
|
||||
// If it can't just be cast to an int, try to parse string into an
|
||||
// execution policy.
|
||||
return ExecutionPolicyString(raw)
|
||||
}
|
||||
|
|
|
@ -188,6 +188,13 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
if p.config.ExecutionPolicy > 7 {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf(`Invalid execution `+
|
||||
`policy provided. Please supply one of: "bypass", "allsigned",`+
|
||||
` "default", "remotesigned", "restricted", "undefined", `+
|
||||
`"unrestricted", "none".`))
|
||||
}
|
||||
|
||||
if errs != nil {
|
||||
return errs
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package powershell_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/provisioner/powershell"
|
||||
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/packer/command"
|
||||
"github.com/hashicorp/packer/helper/tests/acc"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
const TestProvisionerName = "powershell"
|
||||
|
||||
func TestPowershellProvisioner_Inline(t *testing.T) {
|
||||
acc.TestProvisionersPreCheck(TestProvisionerName, t)
|
||||
|
||||
testProvisioner := PowershellProvisionerAccTest{"powershell-inline-provisioner.txt"}
|
||||
acc.TestProvisionersAgainstBuilders(&testProvisioner, t)
|
||||
}
|
||||
|
||||
func TestPowershellProvisioner_Script(t *testing.T) {
|
||||
acc.TestProvisionersPreCheck(TestProvisionerName, t)
|
||||
|
||||
testProvisioner := PowershellProvisionerAccTest{"powershell-script-provisioner.txt"}
|
||||
acc.TestProvisionersAgainstBuilders(&testProvisioner, t)
|
||||
}
|
||||
|
||||
type PowershellProvisionerAccTest struct {
|
||||
ConfigName string
|
||||
}
|
||||
|
||||
func (s *PowershellProvisionerAccTest) GetName() string {
|
||||
return TestProvisionerName
|
||||
}
|
||||
|
||||
func (s *PowershellProvisionerAccTest) GetConfig() (string, error) {
|
||||
filePath := filepath.Join("./test-fixtures", s.ConfigName)
|
||||
config, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("os.Open:%v", err)
|
||||
}
|
||||
defer config.Close()
|
||||
|
||||
file, err := ioutil.ReadAll(config)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ioutil.ReadAll:%v", err)
|
||||
}
|
||||
return string(file), nil
|
||||
}
|
||||
|
||||
func (s *PowershellProvisionerAccTest) GetProvisionerStore() packer.MapOfProvisioner {
|
||||
return packer.MapOfProvisioner{
|
||||
TestProvisionerName: func() (packer.Provisioner, error) { return &powershell.Provisioner{}, nil },
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PowershellProvisionerAccTest) IsCompatible(builder string, vmOS string) bool {
|
||||
return vmOS == "windows"
|
||||
}
|
||||
|
||||
func (s *PowershellProvisionerAccTest) RunTest(c *command.BuildCommand, args []string) error {
|
||||
UUID := os.Getenv("PACKER_RUN_UUID")
|
||||
if UUID == "" {
|
||||
UUID, _ = uuid.GenerateUUID()
|
||||
os.Setenv("PACKER_RUN_UUID", UUID)
|
||||
}
|
||||
|
||||
if code := c.Run(args); code != 0 {
|
||||
ui := c.Meta.Ui.(*packer.BasicUi)
|
||||
out := ui.Writer.(*bytes.Buffer)
|
||||
err := ui.ErrorWriter.(*bytes.Buffer)
|
||||
return fmt.Errorf(
|
||||
"Bad exit code.\n\nStdout:\n\n%s\n\nStderr:\n\n%s",
|
||||
out.String(),
|
||||
err.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -3,6 +3,7 @@ package powershell
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
|
@ -564,6 +566,113 @@ func TestProvisioner_createFlattenedElevatedEnvVars_windows(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestProvisionerCorrectlyInterpolatesValidExitCodes(t *testing.T) {
|
||||
type testCases struct {
|
||||
Input interface{}
|
||||
Expected []int
|
||||
}
|
||||
validExitCodeTests := []testCases{
|
||||
{"0", []int{0}},
|
||||
{[]string{"0"}, []int{0}},
|
||||
{[]int{0, 12345}, []int{0, 12345}},
|
||||
{[]string{"0", "12345"}, []int{0, 12345}},
|
||||
{"0,12345", []int{0, 12345}},
|
||||
}
|
||||
|
||||
for _, tc := range validExitCodeTests {
|
||||
p := new(Provisioner)
|
||||
config := testConfig()
|
||||
config["valid_exit_codes"] = tc.Input
|
||||
err := p.Prepare(config)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Shouldn't have had error interpolating exit codes")
|
||||
}
|
||||
assert.ElementsMatchf(t, p.config.ValidExitCodes, tc.Expected,
|
||||
fmt.Sprintf("expected exit codes to be: %#v, got %#v.", p.config.ValidExitCodes, tc.Expected))
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisionerCorrectlyInterpolatesExecutionPolicy(t *testing.T) {
|
||||
type testCases struct {
|
||||
Input interface{}
|
||||
Expected ExecutionPolicy
|
||||
ErrExpected bool
|
||||
}
|
||||
tests := []testCases{
|
||||
{
|
||||
Input: "bypass",
|
||||
Expected: ExecutionPolicy(0),
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "allsigned",
|
||||
Expected: ExecutionPolicy(1),
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "default",
|
||||
Expected: ExecutionPolicy(2),
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "remotesigned",
|
||||
Expected: ExecutionPolicy(3),
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "restricted",
|
||||
Expected: ExecutionPolicy(4),
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "undefined",
|
||||
Expected: ExecutionPolicy(5),
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "unrestricted",
|
||||
Expected: ExecutionPolicy(6),
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "none",
|
||||
Expected: ExecutionPolicy(7),
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "0", // User can supply a valid number for policy, too
|
||||
Expected: 0,
|
||||
ErrExpected: false,
|
||||
},
|
||||
{
|
||||
Input: "invalid",
|
||||
Expected: 0,
|
||||
ErrExpected: true,
|
||||
},
|
||||
{
|
||||
Input: "100", // If number is invalid policy, reject.
|
||||
Expected: 100,
|
||||
ErrExpected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
p := new(Provisioner)
|
||||
config := testConfig()
|
||||
config["execution_policy"] = tc.Input
|
||||
err := p.Prepare(config)
|
||||
|
||||
if (err != nil) != tc.ErrExpected {
|
||||
t.Fatalf("Either err was expected, or shouldn't have happened: %#v", tc)
|
||||
}
|
||||
if err == nil {
|
||||
assert.Equal(t, p.config.ExecutionPolicy, tc.Expected,
|
||||
fmt.Sprintf("expected %#v, got %#v.", p.config.ExecutionPolicy, tc.Expected))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) {
|
||||
var flattenedEnvVars string
|
||||
config := testConfig()
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "powershell",
|
||||
"environment_vars": "PackerRunUUID={{build `PackerRunUUID`}},ID={{build `ID`}}",
|
||||
"inline": [
|
||||
"Write-Host \"$env:ID for provisioner.$env:PackerRunUUID\""
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"type": "powershell",
|
||||
"script": "../../provisioner/powershell/test-fixtures/scripts/sample_script.ps1",
|
||||
"environment_vars": [
|
||||
"VAR1=A$Dollar",
|
||||
"VAR2=A`Backtick",
|
||||
"VAR3=A'SingleQuote",
|
||||
"VAR4=A\"DoubleQuote"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
write-output("packer_build_name is automatically set for you, or you can set it in your builder variables; the default for this builder is: " + $env:packer_build_name )
|
||||
write-output("remember that escaping variables in powershell requires backticks; for example var1 from our config is " + $env:var1 )
|
||||
write-output("likewise, var2 is " + $env:var2 )
|
||||
write-output("and var3 is " + $env:var3 )
|
||||
|
|
@ -3,13 +3,15 @@ package shell_test
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/hashicorp/packer/helper/tests/acc"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/helper/tests/acc"
|
||||
"github.com/hashicorp/packer/provisioner/file"
|
||||
"github.com/hashicorp/packer/provisioner/shell"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
|
||||
"github.com/hashicorp/go-uuid"
|
||||
|
@ -18,10 +20,7 @@ import (
|
|||
)
|
||||
|
||||
func TestShellProvisioner(t *testing.T) {
|
||||
p := os.Getenv("ACC_TEST_PROVISIONERS")
|
||||
if p != "all" && !strings.Contains(p, "shell") {
|
||||
t.Skip()
|
||||
}
|
||||
acc.TestProvisionersPreCheck("shell", t)
|
||||
acc.TestProvisionersAgainstBuilders(new(ShellProvisionerAccTest), t)
|
||||
}
|
||||
|
||||
|
@ -40,13 +39,13 @@ func (s *ShellProvisionerAccTest) GetConfig() (string, error) {
|
|||
defer config.Close()
|
||||
|
||||
file, err := ioutil.ReadAll(config)
|
||||
return string(file), nil
|
||||
return string(file), err
|
||||
}
|
||||
|
||||
func (s *ShellProvisionerAccTest) GetProvisionerStore() packer.MapOfProvisioner {
|
||||
return packer.MapOfProvisioner{
|
||||
"shell": func() (packer.Provisioner, error) { return command.Provisioners["shell"], nil },
|
||||
"file": func() (packer.Provisioner, error) { return command.Provisioners["file"], nil },
|
||||
"shell": func() (packer.Provisioner, error) { return &shell.Provisioner{}, nil },
|
||||
"file": func() (packer.Provisioner, error) { return &file.Provisioner{}, nil },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -328,7 +328,7 @@ func funcGenSed(ctx *Context) interface{} {
|
|||
return func(expression string, inputString string) (string, error) {
|
||||
return "", errors.New("template function `sed` is deprecated " +
|
||||
"use `replace` or `replace_all` instead." +
|
||||
"Documentation: https://www.packer.io/docs/templates/engine.html")
|
||||
"Documentation: https://www.packer.io/docs/templates/engine")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# This file is for unifying the coding style for different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
[{*.md,*.json}]
|
||||
max_line_length = null
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
...require('@hashicorp/nextjs-scripts/.eslintrc.js'),
|
||||
ignorePatterns: ['public/']
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
node_modules
|
||||
.DS_Store
|
||||
.next
|
||||
out
|
||||
.mdx-data
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"ignore": {
|
||||
"marked": {
|
||||
"versions": "0.8.2",
|
||||
"reason": "IE breaks"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
FROM node:10.16.3-alpine
|
||||
RUN apk add --update --no-cache git make g++ automake autoconf libtool nasm libpng-dev
|
||||
|
||||
COPY ./package.json /website/package.json
|
||||
COPY ./package-lock.json /website/package-lock.json
|
||||
WORKDIR /website
|
||||
RUN npm install
|
|
@ -1,3 +0,0 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem "middleman-hashicorp", "0.3.44"
|
|
@ -1,161 +0,0 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (4.2.11.1)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
autoprefixer-rails (9.7.4)
|
||||
execjs
|
||||
bootstrap-sass (3.4.1)
|
||||
autoprefixer-rails (>= 5.2.1)
|
||||
sassc (>= 2.0.0)
|
||||
builder (3.2.4)
|
||||
capybara (2.4.4)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
chunky_png (1.3.11)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.12.2)
|
||||
compass (1.0.3)
|
||||
chunky_png (~> 1.2)
|
||||
compass-core (~> 1.0.2)
|
||||
compass-import-once (~> 1.0.5)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
sass (>= 3.3.13, < 3.5)
|
||||
compass-core (1.0.3)
|
||||
multi_json (~> 1.0)
|
||||
sass (>= 3.3.0, < 3.5)
|
||||
compass-import-once (1.0.5)
|
||||
sass (>= 3.2, < 3.5)
|
||||
em-websocket (0.5.1)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.2.7)
|
||||
execjs (2.7.0)
|
||||
ffi (1.12.2)
|
||||
haml (5.1.2)
|
||||
temple (>= 0.8.0)
|
||||
tilt
|
||||
hike (1.2.3)
|
||||
hooks (0.4.1)
|
||||
uber (~> 0.0.14)
|
||||
http_parser.rb (0.6.0)
|
||||
i18n (0.7.0)
|
||||
json (2.3.0)
|
||||
kramdown (1.17.0)
|
||||
listen (3.0.8)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
middleman (3.4.1)
|
||||
coffee-script (~> 2.2)
|
||||
compass (>= 1.0.0, < 2.0.0)
|
||||
compass-import-once (= 1.0.5)
|
||||
execjs (~> 2.0)
|
||||
haml (>= 4.0.5)
|
||||
kramdown (~> 1.2)
|
||||
middleman-core (= 3.4.1)
|
||||
middleman-sprockets (>= 3.1.2)
|
||||
sass (>= 3.4.0, < 4.0)
|
||||
uglifier (~> 2.5)
|
||||
middleman-core (3.4.1)
|
||||
activesupport (~> 4.1)
|
||||
bundler (~> 1.1)
|
||||
capybara (~> 2.4.4)
|
||||
erubis
|
||||
hooks (~> 0.3)
|
||||
i18n (~> 0.7.0)
|
||||
listen (~> 3.0.3)
|
||||
padrino-helpers (~> 0.12.3)
|
||||
rack (>= 1.4.5, < 2.0)
|
||||
thor (>= 0.15.2, < 2.0)
|
||||
tilt (~> 1.4.1, < 2.0)
|
||||
middleman-hashicorp (0.3.44)
|
||||
bootstrap-sass (~> 3.3)
|
||||
builder (~> 3.2)
|
||||
middleman (~> 3.4)
|
||||
middleman-livereload (~> 3.4)
|
||||
middleman-syntax (~> 3.0)
|
||||
redcarpet (~> 3.3)
|
||||
turbolinks (~> 5.0)
|
||||
middleman-livereload (3.4.6)
|
||||
em-websocket (~> 0.5.1)
|
||||
middleman-core (>= 3.3)
|
||||
rack-livereload (~> 0.3.15)
|
||||
middleman-sprockets (3.5.0)
|
||||
middleman-core (>= 3.3)
|
||||
sprockets (~> 2.12.1)
|
||||
sprockets-helpers (~> 1.1.0)
|
||||
sprockets-sass (~> 1.3.0)
|
||||
middleman-syntax (3.2.0)
|
||||
middleman-core (>= 3.2)
|
||||
rouge (~> 3.2)
|
||||
mime-types (3.3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2019.1009)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.14.0)
|
||||
multi_json (1.14.1)
|
||||
nokogiri (1.10.9)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
padrino-helpers (0.12.9)
|
||||
i18n (~> 0.6, >= 0.6.7)
|
||||
padrino-support (= 0.12.9)
|
||||
tilt (>= 1.4.1, < 3)
|
||||
padrino-support (0.12.9)
|
||||
activesupport (>= 3.1)
|
||||
rack (1.6.13)
|
||||
rack-livereload (0.3.17)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rb-fsevent (0.10.3)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
redcarpet (3.5.0)
|
||||
rouge (3.16.0)
|
||||
sass (3.4.25)
|
||||
sassc (2.2.1)
|
||||
ffi (~> 1.9)
|
||||
sprockets (2.12.5)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sprockets-helpers (1.1.0)
|
||||
sprockets (~> 2.0)
|
||||
sprockets-sass (1.3.1)
|
||||
sprockets (~> 2.0)
|
||||
tilt (~> 1.1)
|
||||
temple (0.8.2)
|
||||
thor (1.0.1)
|
||||
thread_safe (0.3.6)
|
||||
tilt (1.4.1)
|
||||
turbolinks (5.2.1)
|
||||
turbolinks-source (~> 5.2)
|
||||
turbolinks-source (5.2.0)
|
||||
tzinfo (1.2.6)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.0.15)
|
||||
uglifier (2.7.2)
|
||||
execjs (>= 0.3.0)
|
||||
json (>= 1.8.0)
|
||||
xpath (2.1.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
middleman-hashicorp (= 0.3.44)
|
||||
|
||||
BUNDLED WITH
|
||||
1.17.3
|
|
@ -1,30 +1,54 @@
|
|||
configure_cache:
|
||||
mkdir -p tmp/cache
|
||||
|
||||
build: configure_cache
|
||||
@echo "==> Starting build in Docker..."
|
||||
@docker run \
|
||||
--interactive \
|
||||
--rm \
|
||||
--tty \
|
||||
--volume "$(shell pwd):/opt/buildhome/repo" \
|
||||
--volume "$(shell pwd)/tmp/cache:/opt/buildhome/cache" \
|
||||
--env "ENV=production" \
|
||||
netlify/build \
|
||||
build middleman build --verbose
|
||||
|
||||
website: configure_cache
|
||||
# Default: run this if working on the website locally to run in watch mode.
|
||||
website:
|
||||
@echo "==> Downloading latest Docker image..."
|
||||
@docker pull hashicorp/packer-website
|
||||
@echo "==> Starting website in Docker..."
|
||||
@docker run \
|
||||
--interactive \
|
||||
--rm \
|
||||
--tty \
|
||||
--volume "$(shell pwd):/opt/buildhome/repo" \
|
||||
--volume "$(shell pwd)/tmp/cache:/opt/buildhome/cache" \
|
||||
--publish "4567:4567" \
|
||||
--publish "35729:35729" \
|
||||
--env "ENV=production" \
|
||||
netlify/build \
|
||||
build middleman
|
||||
--workdir "/website" \
|
||||
--volume "$(shell pwd):/website" \
|
||||
--volume "/website/node_modules" \
|
||||
--publish "3000:3000" \
|
||||
hashicorp/packer-website \
|
||||
npm start
|
||||
|
||||
.PHONY: build website
|
||||
# This command will generate a static version of the website to the "out" folder.
|
||||
build:
|
||||
@echo "==> Downloading latest Docker image..."
|
||||
@docker pull hashicorp/packer-website
|
||||
@echo "==> Starting build in Docker..."
|
||||
@docker run \
|
||||
--interactive \
|
||||
--rm \
|
||||
--tty \
|
||||
--workdir "/website" \
|
||||
--volume "$(shell pwd):/website" \
|
||||
--volume "/website/node_modules" \
|
||||
hashicorp/packer-website \
|
||||
npm run static
|
||||
|
||||
# If you are changing node dependencies locally, run this to generate a new
|
||||
# local Docker image with the dependency changes included.
|
||||
build-image:
|
||||
@echo "==> Building Docker image..."
|
||||
@docker build -t hashicorp-packer-website-local .
|
||||
|
||||
# Use this if you have run `build-image` to use the locally built image
|
||||
# rather than our CI-generated image to test dependency changes.
|
||||
website-local:
|
||||
@echo "==> Starting website in Docker..."
|
||||
@docker run \
|
||||
--interactive \
|
||||
--rm \
|
||||
--tty \
|
||||
--workdir "/website" \
|
||||
--volume "$(shell pwd):/website" \
|
||||
--volume "/website/node_modules" \
|
||||
--publish "3000:3000" \
|
||||
hashicorp-packer-website-local \
|
||||
npm start
|
||||
|
||||
.DEFAULT_GOAL := website
|
||||
.PHONY: build build-image website website-local
|
||||
|
|
|
@ -1,22 +1,193 @@
|
|||
# Packer Website
|
||||
|
||||
This subdirectory contains the entire source for the [Packer Website][packer].
|
||||
This is a [Middleman][middleman] project, which builds a static site from these
|
||||
source files.
|
||||
[![Netlify Status](https://img.shields.io/netlify/f7fa8963-0022-4a0e-9ccf-f5385355906b?style=flat-square)](https://app.netlify.com/sites/packer-docs-platform/deploys)
|
||||
|
||||
This subdirectory contains the entire source for the [Packer Website](https://packer.io/). This is a [NextJS](https://nextjs.org/) project, which builds a static site from these source files.
|
||||
|
||||
## Contributions Welcome!
|
||||
|
||||
If you find a typo or you feel like you can improve the HTML, CSS, or
|
||||
JavaScript, we welcome contributions. Feel free to open issues or pull requests
|
||||
like any normal GitHub project, and we'll merge it in.
|
||||
If you find a typo or you feel like you can improve the HTML, CSS, or JavaScript, we welcome contributions. Feel free to open issues or pull requests like any normal GitHub project, and we'll merge it in 🚀
|
||||
|
||||
## Running the Site Locally
|
||||
|
||||
1. Install [Docker](https://docs.docker.com/engine/installation/) if you have not already done so
|
||||
2. Clone this repo and run `make website`
|
||||
The website can be run locally through node.js or Docker. If you choose to run through Docker, everything will be a little bit slower due to the additional overhead, so for frequent contributors it may be worth it to use node. Also if you are a vim user, it's also worth noting that vim's swapfile usage can cause issues for the live reload functionality. In order to avoid these issues, make sure you have run `:set backupcopy=yes` within vim.
|
||||
|
||||
Then open up `http://localhost:4567`. Note that some URLs you may need to append
|
||||
".html" to make them work (in the navigation).
|
||||
### With Docker
|
||||
|
||||
[middleman]: https://www.middlemanapp.com
|
||||
[packer]: https://www.packer.io
|
||||
Running the site locally is simple. Provided you have Docker installed, clone this repo, run `make`, and then visit `http://localhost:3000`.
|
||||
|
||||
The docker image is pre-built with all the website dependencies installed, which is what makes it so quick and simple, but also means if you need to change dependencies and test the changes within Docker, you'll need a new image. If this is something you need to do, you can run `make build-image` to generate a local Docker image with updated dependencies, then `make website-local` to use that image and preview.
|
||||
|
||||
### With Node
|
||||
|
||||
If your local development environment has a supported version (v10.0.0+) of [node installed](https://nodejs.org/en/) you can run:
|
||||
|
||||
- `npm install`
|
||||
- `npm start`
|
||||
|
||||
and then visit `http://localhost:3000`.
|
||||
|
||||
If you pull down new code from github, you should run `npm install` again. Otherwise, there's no need to re-run `npm install` each time the site is run, you can just run `npm start` to get it going.
|
||||
|
||||
## Editing Content
|
||||
|
||||
Documentation content is written in [Markdown](https://www.markdownguide.org/cheat-sheet/) and you'll find all files listed under the `/pages` directory.
|
||||
|
||||
To create a new page with Markdown, create a file ending in `.mdx` in the `pages/` directory. The path in the pages directory will be the URL route. For example, `pages/hello/world.mdx` will be served from the `/hello/world` URL.
|
||||
|
||||
This file can be standard Markdown and also supports [YAML frontmatter](https://middlemanapp.com/basics/frontmatter/). YAML frontmatter is optional, there are defaults for all keys.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: 'My Title'
|
||||
description: "A thorough, yet succinct description of the page's contents"
|
||||
---
|
||||
|
||||
```
|
||||
|
||||
The significant keys in the YAML frontmatter are:
|
||||
|
||||
- `title` `(string)` - This is the title of the page that will be set in the HTML title.
|
||||
- `description` `(string)` - This is a description of the page that will be set in the HTML description.
|
||||
|
||||
> ⚠️Since `api` is a reserved directory within NextJS, all `/api/**` pages are listed under the `/pages/api-docs` path.
|
||||
|
||||
### Editing Sidebars
|
||||
|
||||
The structure of the sidebars are controlled by files in the [`/data` directory](data).
|
||||
|
||||
- Edit [this file](data/docs-navigation.js) to change the **docs** sidebar
|
||||
- Edit [this file](data/guides-navigation.js) to change the **guides** sidebar
|
||||
- Edit [this file](data/intro-navigation.js) to change the **intro** sidebar
|
||||
|
||||
To nest sidebar items, you'll want to add a new `category` key/value accompanied by the appropriate embedded `content` values.
|
||||
|
||||
- `category` values will be **directory names** within the `pages` directory
|
||||
- `content` values will be **file names** within their appropriately nested directory.
|
||||
|
||||
### Creating New Pages
|
||||
|
||||
There is currently a small bug with new page creation - if you create a new page and link it up via subnav data while the server is running, it will report an error saying the page was not found. This can be resolved by restarting the server.
|
||||
|
||||
### Changing the Release Version
|
||||
|
||||
To change the version of Packer displayed for download on the website, head over to `data/version.js` and change the number there. It's important to note that the version number must match a version that has been released and is live on `releases.hashicorp.com` -- if it does not, the website will be unable to fetch links to the binaries and will not compile. So this version number should be changed _only after a release_.
|
||||
|
||||
#### Displaying a Prerelease
|
||||
|
||||
If there is a prerelease of any type that should be displayed on the downloads page, this can be done by editing `pages/downloads/index.jsx`. By default, the download component might look something like this:
|
||||
|
||||
```jsx
|
||||
<ProductDownloader
|
||||
product="Packer"
|
||||
version={VERSION}
|
||||
downloads={downloadData}
|
||||
community="/resources"
|
||||
/>
|
||||
```
|
||||
|
||||
To add a prerelease, an extra `prerelease` property can be added to the component as such:
|
||||
|
||||
```jsx
|
||||
<ProductDownloader
|
||||
product="Packer"
|
||||
version={VERSION}
|
||||
downloads={downloadData}
|
||||
community="/resources"
|
||||
prerelease={{
|
||||
type: 'release candidate', // the type of prerelease: beta, release candidate, etc.
|
||||
name: 'v1.0.0', // the name displayed in text on the website
|
||||
version: '1.0.0-rc1', // the actual version tag that was pushed to releases.hashicorp.com
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
This configuration would display something like the following text on the website, emphasis added to the configurable parameters:
|
||||
|
||||
```
|
||||
A {{ release candidate }} for Packer {{ v1.0.0 }} is available! The release can be <a href='https://releases.hashicorp.com/packer/{{ 1.0.0-rc1 }}'>downloaded here</a>.
|
||||
```
|
||||
|
||||
You may customize the parameters in any way you'd like. To remove a prerelease from the website, simply delete the `prerelease` paremeter from the above component.
|
||||
|
||||
|
||||
### Markdown Enhancements
|
||||
|
||||
There are several custom markdown plugins that are available by default that enhance standard markdown to fit our use cases. This set of plugins introduces a couple instances of custom syntax, and a couple specific pitfalls that are not present by default with markdown, detailed below:
|
||||
|
||||
- If you see the symbols `~>`, `->`, `=>`, or `!>`, these represent [custom alerts](https://github.com/hashicorp/remark-plugins/tree/master/plugins/paragraph-custom-alerts#paragraph-custom-alerts). These render as colored boxes to draw the user's attention to some type of aside.
|
||||
- If you see `@include '/some/path.mdx'`, this is a [markdown include](https://github.com/hashicorp/remark-plugins/tree/master/plugins/include-markdown#include-markdown-plugin). It's worth noting as well that all includes resolve from `website/pages/partials` by default.
|
||||
- If you see `# Headline ((#slug))`, this is an example of an [anchor link alias](https://github.com/hashicorp/remark-plugins/tree/je.anchor-link-adjustments/plugins/anchor-links#anchor-link-aliases). It adds an extra permalink to a headline for compatibility and is removed from the output.
|
||||
- Due to [automatically generated permalinks](https://github.com/hashicorp/remark-plugins/tree/je.anchor-link-adjustments/plugins/anchor-links#anchor-links), any text changes to _headlines_ or _list items that begin with inline code_ can and will break existing permalinks. Be very cautious when changing either of these two text items.
|
||||
|
||||
Headlines are fairly self-explanitory, but here's an example of how list items that begin with inline code look.
|
||||
|
||||
```markdown
|
||||
- this is a normal list item
|
||||
- `this` is a list item that begins with inline code
|
||||
```
|
||||
|
||||
Its worth noting that _only the inline code at the beginning of the list item_ will cause problems if changed. So if you changed the above markup to...
|
||||
|
||||
```markdown
|
||||
- lsdhfhksdjf
|
||||
- `this` jsdhfkdsjhkdsfjh
|
||||
```
|
||||
|
||||
...while it perhaps would not be an improved user experience, no links would break because of it. The best approach is to **avoid changing headlines and inline code at the start of a list item**. If you must change one of these items, make sure to tag someone from the digital marketing development team on your pull request, they will help to ensure as much compatibility as possible.
|
||||
|
||||
### Redirects
|
||||
|
||||
This website structures URLs based on the filesystem layout. This means that if a file is moved, removed, or a folder is re-organized, links will break. If a path change is necessary, it can be mitigated using redirects.
|
||||
|
||||
To add a redirect, head over to the `_redirects` file - the format is fairly simple. On the left is the current path, and on the right is the path that should be redirected to. It's important to note that if there are links to a `.html` version of a page, that must also be explicitly redirected. For example:
|
||||
|
||||
```
|
||||
/foo /bar
|
||||
/foo.html /bar
|
||||
```
|
||||
|
||||
This redirect rule will send all incoming links to `/foo` and `/foo.html` to `/bar`. For more details on the redirects file format, [check out the docs on netlify](https://docs.netlify.com/routing/redirects/rewrites-proxies).
|
||||
|
||||
There are a couple important caveats with redirects. First, redirects are applied at the hosting layer, and therefore will not work by default in local dev mode. To test in local dev mode, you can use [`netlify dev`](https://www.netlify.com/products/dev/), or just push a commit and check using the deploy preview.
|
||||
|
||||
Second, redirects do not apply to client-side navigation. By default, all links in the navigation and docs sidebar will navigate purely on the client side, which makes navigation through the docs significantly faster, especially for those with low-end devices and/or weak internet connections. In the future, we plan to convert all internal links within docs pages to behave this way as well. This means that if there is a link on this website to a given piece of content that has changed locations in some way, we need to also _directly change existing links to the content_. This way, if a user clicks a link that navigates on the client side, or if they hit the url directly and the page renders from the server side, either one will work perfectly.
|
||||
|
||||
Let's look at an example. Say you have a page called `/docs/foo` which needs to be moved to `/docs/nested/foo`. Additionally, this is a page that has been around for a while and we know there are links into `/docs/foo.html` left over from our previous website structure. First, we move the page, then adjust the docs sidenav, in `data/docs-navigation.js`. Find the category the page is in, and move it into the appropriate subcategory. Next, we add to `_redirects` as such:
|
||||
|
||||
```
|
||||
/foo /nested/foo
|
||||
/foo.html /nested/foo
|
||||
```
|
||||
|
||||
Finally, we run a global search for internal links to `/foo`, and make sure to adjust them to be `/nested/foo` - this is to ensure that client-side navigation still works correctly. _Adding a redirect alone is not enough_.
|
||||
|
||||
One more example - let's say that content is being moved to an external website. A common example is guides moving to `learn.hashicorp.com`. In this case, we take all the same steps, except that we need to make a different type of change to the `docs-navigation` file. If previously the structure looked like:
|
||||
|
||||
```js
|
||||
{
|
||||
category: 'docs',
|
||||
content: [
|
||||
'foo'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
If we no longer want the link to be in the side nav, we can simply remove it. If we do still want the link in the side nav, but pointing to an external destnation, we need to slightly change the structure as such:
|
||||
|
||||
```js
|
||||
{
|
||||
category: 'docs',
|
||||
content: [
|
||||
{ title: 'Foo Title', href: 'https://learn.hashicorp.com/vault/foo' }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
As the majority of items in the side nav are internal links, the structure makes it as easy as possible to represent these links. This alternate syntax is the most concise manner than an external link can be represented. External links can be used anywhere within the docs sidenav.
|
||||
|
||||
It's also worth noting that it is possible to do glob-based redirects, for example matching `/docs/*`, and you may see this pattern in the `_redirects` file. This type of redirect is much higher risk and the behavior is a bit more nuanced, so if you need to add a glob redirect, please reach out to the website maintainers and ask about it first.
|
||||
|
||||
### Deployment
|
||||
|
||||
This website is hosted on Netlify and configured to automatically deploy anytime you push code to the `stable-website` branch. Any time a pull request is submitted that changes files within the `website` folder, a deployment preview will appear in the github checks which can be used to validate the way docs changes will look live. Deployments from `stable-website` will look and behave the same way as deployment previews.
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
# REDIRECTS FILE
|
||||
#
|
||||
# See https://www.netlify.com/docs/redirects/ for documentation. Please do not
|
||||
# modify or delete existing redirects without first verifying internally.
|
||||
|
||||
/docs/installation.html /docs/install 301!
|
||||
/docs/command-line/machine-readable.html /docs/commands 301!
|
||||
/docs/command-line/introduction.html /docs/commands 301!
|
||||
/docs/templates/introduction.html /docs/templates 301!
|
||||
/docs/builders/azure-setup.html /docs/builders/azure 301!
|
||||
/docs/templates/veewee-to-packer.html /guides/veewee-to-packer 301!
|
||||
/docs/extend/developing-plugins.html /docs/extending/plugins 301!
|
||||
/docs/extending/developing-plugins.html /docs/extending/plugins 301!
|
||||
/docs/extend/builder.html /docs/extending/custom-builders 301!
|
||||
/docs/getting-started/setup.html /docs/getting-started/install 301!
|
||||
/docs/other/community.html /community-tools 301!
|
||||
/downloads-community.html /community-tools 301!
|
||||
/community/index.html /community 301!
|
||||
/docs/other/environmental-variables.html /docs/other/environment-variables 301!
|
||||
/docs/platforms.html /docs/builders 301!
|
||||
/intro/platforms.html /docs/builders 301!
|
||||
/docs/templates/configuration-templates.html /docs/templates/engine 301!
|
||||
/docs/machine-readable/* /docs/commands 301!
|
||||
/docs/command-line/* /docs/commands/:splat 200
|
||||
/docs/extend/* /docs/extending/:splat 200
|
||||
|
||||
/intro/getting-started/install /intro/getting-started 301!
|
||||
/intro/getting-started/install.html /intro/getting-started 301!
|
||||
|
||||
/docs/basics/terminology /docs/terminology 301!
|
||||
/docs/basics/terminology.html /docs/terminology 301!
|
||||
|
||||
/docs/other/* /docs/:splat 200
|
||||
|
||||
/docs/configuration/from-1.5/* /docs/from-1.5/:splat 200
|
||||
/docs/configuration/from-1.5/*/overview /docs/from-1.5/:splat 200
|
||||
/docs/configuration/from-1.5/*/overview.html /docs/from-1.5/:splat 200
|
||||
|
||||
/docs/builders/amazon.html /docs/builders/amazon 301!
|
||||
/docs/builders/amazon-*.html /docs/builders/amazon/:splat 200
|
||||
/docs/builders/amazon-* /docs/builders/amazon/:splat 200
|
||||
|
||||
/docs/builders/azure.html /docs/builders/azure 301!
|
||||
/docs/builders/azure-*.html /docs/builders/azure/:splat 200
|
||||
/docs/builders/azure-* /docs/builders/azure/:splat 200
|
||||
|
||||
/docs/builders/hyperv.html /docs/builders/hyperv 301!
|
||||
/docs/builders/hyperv-*.html /docs/builders/hyperv/:splat 200
|
||||
/docs/builders/hyperv-* /docs/builders/hyperv/:splat 200
|
||||
|
||||
/docs/builders/oracle.html /docs/builders/oracle 301!
|
||||
/docs/builders/oracle-*.html /docs/builders/oracle/:splat 200
|
||||
/docs/builders/oracle-* /docs/builders/oracle/:splat 200
|
||||
|
||||
/docs/builders/outscale.html /docs/builders/outscale 301!
|
||||
/docs/builders/osc-*.html /docs/builders/outscale/:splat 200
|
||||
/docs/builders/osc-* /docs/builders/outscale/:splat 200
|
||||
|
||||
/docs/builders/parallels.html /docs/builders/parallels 301!
|
||||
/docs/builders/parallels-*.html /docs/builders/parallels/:splat 200
|
||||
/docs/builders/parallels-* /docs/builders/parallels/:splat 200
|
||||
|
||||
/docs/builders/virtualbox.html /docs/builders/virtualbox 301!
|
||||
/docs/builders/virtualbox-*.html /docs/builders/virtualbox/:splat 200
|
||||
/docs/builders/virtualbox-* /docs/builders/virtualbox/:splat 200
|
||||
|
||||
/docs/builders/vmware.html /docs/builders/vmware 301!
|
||||
/docs/builders/vmware-*.html /docs/builders/vmware/:splat 200
|
||||
/docs/builders/vmware-* /docs/builders/vmware/:splat 200
|
||||
/docs/builders/vsphere-*.html /docs/builders/vmware/vsphere-:splat 200
|
||||
/docs/builders/vsphere-* /docs/builders/vmware/vsphere-:splat 200
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
presets: ['next/babel'],
|
||||
plugins: ['import-glob-array']
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
export default function Footer({ openConsentManager }) {
|
||||
return (
|
||||
<footer className="g-footer">
|
||||
<div className="g-container">
|
||||
<div className="left">
|
||||
<Link href="/intro">
|
||||
<a>Intro</a>
|
||||
</Link>
|
||||
<Link href="/guides">
|
||||
<a>Guides</a>
|
||||
</Link>
|
||||
<Link href="/docs">
|
||||
<a>Docs</a>
|
||||
</Link>
|
||||
<Link href="/community">
|
||||
<a>Community</a>
|
||||
</Link>
|
||||
<a href="https://hashicorp.com/privacy">Privacy</a>
|
||||
<Link href="/security">
|
||||
<a>Security</a>
|
||||
</Link>
|
||||
<Link href="/files/press-kit.zip">
|
||||
<a>Press Kit</a>
|
||||
</Link>
|
||||
<a onClick={openConsentManager}>Consent Manager</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
.g-footer {
|
||||
padding: 25px 0 17px 0;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
|
||||
& .g-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
& a {
|
||||
color: black;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.25s ease;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
& .left > a {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue