parent
2dbfef5750
commit
6fa213235f
|
@ -28,6 +28,7 @@ import (
|
||||||
googlecomputeexportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-export"
|
googlecomputeexportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-export"
|
||||||
googlecomputeimportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-import"
|
googlecomputeimportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-import"
|
||||||
ncloudbuilder "github.com/hashicorp/packer-plugin-ncloud/builder/ncloud"
|
ncloudbuilder "github.com/hashicorp/packer-plugin-ncloud/builder/ncloud"
|
||||||
|
openstackbuilder "github.com/hashicorp/packer-plugin-openstack/builder/openstack"
|
||||||
oscbsubuilder "github.com/hashicorp/packer-plugin-outscale/builder/osc/bsu"
|
oscbsubuilder "github.com/hashicorp/packer-plugin-outscale/builder/osc/bsu"
|
||||||
oscbsusurrogatebuilder "github.com/hashicorp/packer-plugin-outscale/builder/osc/bsusurrogate"
|
oscbsusurrogatebuilder "github.com/hashicorp/packer-plugin-outscale/builder/osc/bsusurrogate"
|
||||||
oscbsuvolumebuilder "github.com/hashicorp/packer-plugin-outscale/builder/osc/bsuvolume"
|
oscbsuvolumebuilder "github.com/hashicorp/packer-plugin-outscale/builder/osc/bsuvolume"
|
||||||
|
@ -68,6 +69,7 @@ var VendoredBuilders = map[string]packersdk.Builder{
|
||||||
"docker": new(dockerbuilder.Builder),
|
"docker": new(dockerbuilder.Builder),
|
||||||
"googlecompute": new(googlecomputebuilder.Builder),
|
"googlecompute": new(googlecomputebuilder.Builder),
|
||||||
"ncloud": new(ncloudbuilder.Builder),
|
"ncloud": new(ncloudbuilder.Builder),
|
||||||
|
"openstack": new(openstackbuilder.Builder),
|
||||||
"proxmox": new(proxmoxiso.Builder),
|
"proxmox": new(proxmoxiso.Builder),
|
||||||
"proxmox-iso": new(proxmoxiso.Builder),
|
"proxmox-iso": new(proxmoxiso.Builder),
|
||||||
"proxmox-clone": new(proxmoxclone.Builder),
|
"proxmox-clone": new(proxmoxclone.Builder),
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -45,6 +45,7 @@ require (
|
||||||
github.com/hashicorp/packer-plugin-docker v0.0.7
|
github.com/hashicorp/packer-plugin-docker v0.0.7
|
||||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1
|
github.com/hashicorp/packer-plugin-googlecompute v0.0.1
|
||||||
github.com/hashicorp/packer-plugin-ncloud v0.0.2
|
github.com/hashicorp/packer-plugin-ncloud v0.0.2
|
||||||
|
github.com/hashicorp/packer-plugin-openstack v0.0.1
|
||||||
github.com/hashicorp/packer-plugin-outscale v0.0.1
|
github.com/hashicorp/packer-plugin-outscale v0.0.1
|
||||||
github.com/hashicorp/packer-plugin-parallels v0.0.1
|
github.com/hashicorp/packer-plugin-parallels v0.0.1
|
||||||
github.com/hashicorp/packer-plugin-proxmox v0.0.2
|
github.com/hashicorp/packer-plugin-proxmox v0.0.2
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -474,6 +474,8 @@ github.com/hashicorp/packer-plugin-googlecompute v0.0.1 h1:Shjio88MraB+ocj0VI5+M
|
||||||
github.com/hashicorp/packer-plugin-googlecompute v0.0.1/go.mod h1:MfV898IrEMpKH6wVnvOI5Tkhxm2snf3QxwVqV4k3bNI=
|
github.com/hashicorp/packer-plugin-googlecompute v0.0.1/go.mod h1:MfV898IrEMpKH6wVnvOI5Tkhxm2snf3QxwVqV4k3bNI=
|
||||||
github.com/hashicorp/packer-plugin-ncloud v0.0.2 h1:MGvGkOVfzeosqOSs5dteghLwv9VRcRxTuLoLX1ssUag=
|
github.com/hashicorp/packer-plugin-ncloud v0.0.2 h1:MGvGkOVfzeosqOSs5dteghLwv9VRcRxTuLoLX1ssUag=
|
||||||
github.com/hashicorp/packer-plugin-ncloud v0.0.2/go.mod h1:Hud2R1pkky96TQy3TPTTrr9Kej4b/4dqC/v+uEE0VDY=
|
github.com/hashicorp/packer-plugin-ncloud v0.0.2/go.mod h1:Hud2R1pkky96TQy3TPTTrr9Kej4b/4dqC/v+uEE0VDY=
|
||||||
|
github.com/hashicorp/packer-plugin-openstack v0.0.1 h1:FUaNjKguAipPZZXQ4UiJK6c5+2nS89CRxJHjAsfVyIQ=
|
||||||
|
github.com/hashicorp/packer-plugin-openstack v0.0.1/go.mod h1:L1OTbN24H+izce3v5IyQLdjDdrUigxPWgAQOK920h9A=
|
||||||
github.com/hashicorp/packer-plugin-outscale v0.0.1 h1:BrL8hKypNYrvP3NR+d+xX03SZKB08yTgXPRnH9piUI8=
|
github.com/hashicorp/packer-plugin-outscale v0.0.1 h1:BrL8hKypNYrvP3NR+d+xX03SZKB08yTgXPRnH9piUI8=
|
||||||
github.com/hashicorp/packer-plugin-outscale v0.0.1/go.mod h1:6jEWfJO7TgAbaL3e+St1bN5PoIC/MmDIsYqNUzAHF1w=
|
github.com/hashicorp/packer-plugin-outscale v0.0.1/go.mod h1:6jEWfJO7TgAbaL3e+St1bN5PoIC/MmDIsYqNUzAHF1w=
|
||||||
github.com/hashicorp/packer-plugin-parallels v0.0.1 h1:fcaaiGWdU1+X4IGadXdUhJ2si1ZA3apXS9tMNJXln2A=
|
github.com/hashicorp/packer-plugin-parallels v0.0.1 h1:fcaaiGWdU1+X4IGadXdUhJ2si1ZA3apXS9tMNJXln2A=
|
||||||
|
@ -1192,8 +1194,9 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -0,0 +1,373 @@
|
||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
334
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/access_config.go
generated
vendored
Normal file
334
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/access_config.go
generated
vendored
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
//go:generate packer-sdc struct-markdown
|
||||||
|
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack"
|
||||||
|
"github.com/gophercloud/utils/openstack/clientconfig"
|
||||||
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccessConfig is for common configuration related to openstack access
|
||||||
|
type AccessConfig struct {
|
||||||
|
// The username or id used to connect to the OpenStack service. If not
|
||||||
|
// specified, Packer will use the environment variable OS_USERNAME or
|
||||||
|
// OS_USERID, if set. This is not required if using access token or
|
||||||
|
// application credential instead of password, or if using cloud.yaml.
|
||||||
|
Username string `mapstructure:"username" required:"true"`
|
||||||
|
// Sets username
|
||||||
|
UserID string `mapstructure:"user_id"`
|
||||||
|
// The password used to connect to the OpenStack service. If not specified,
|
||||||
|
// Packer will use the environment variables OS_PASSWORD, if set. This is
|
||||||
|
// not required if using access token or application credential instead of
|
||||||
|
// password, or if using cloud.yaml.
|
||||||
|
Password string `mapstructure:"password" required:"true"`
|
||||||
|
// The URL to the OpenStack Identity service. If not specified, Packer will
|
||||||
|
// use the environment variables OS_AUTH_URL, if set. This is not required
|
||||||
|
// if using cloud.yaml.
|
||||||
|
IdentityEndpoint string `mapstructure:"identity_endpoint" required:"true"`
|
||||||
|
// The tenant ID or name to boot the instance into. Some OpenStack
|
||||||
|
// installations require this. If not specified, Packer will use the
|
||||||
|
// environment variable OS_TENANT_NAME or OS_TENANT_ID, if set. Tenant is
|
||||||
|
// also called Project in later versions of OpenStack.
|
||||||
|
TenantID string `mapstructure:"tenant_id" required:"false"`
|
||||||
|
TenantName string `mapstructure:"tenant_name"`
|
||||||
|
DomainID string `mapstructure:"domain_id"`
|
||||||
|
// The Domain name or ID you are authenticating with. OpenStack
|
||||||
|
// installations require this if identity v3 is used. Packer will use the
|
||||||
|
// environment variable OS_DOMAIN_NAME or OS_DOMAIN_ID, if set.
|
||||||
|
DomainName string `mapstructure:"domain_name" required:"false"`
|
||||||
|
// Whether or not the connection to OpenStack can be done over an insecure
|
||||||
|
// connection. By default this is false.
|
||||||
|
Insecure bool `mapstructure:"insecure" required:"false"`
|
||||||
|
// The name of the region, such as "DFW", in which to launch the server to
|
||||||
|
// create the image. If not specified, Packer will use the environment
|
||||||
|
// variable OS_REGION_NAME, if set.
|
||||||
|
Region string `mapstructure:"region" required:"false"`
|
||||||
|
// The endpoint type to use. Can be any of "internal", "internalURL",
|
||||||
|
// "admin", "adminURL", "public", and "publicURL". By default this is
|
||||||
|
// "public".
|
||||||
|
EndpointType string `mapstructure:"endpoint_type" required:"false"`
|
||||||
|
// Custom CA certificate file path. If omitted the OS_CACERT environment
|
||||||
|
// variable can be used.
|
||||||
|
CACertFile string `mapstructure:"cacert" required:"false"`
|
||||||
|
// Client certificate file path for SSL client authentication. If omitted
|
||||||
|
// the OS_CERT environment variable can be used.
|
||||||
|
ClientCertFile string `mapstructure:"cert" required:"false"`
|
||||||
|
// Client private key file path for SSL client authentication. If omitted
|
||||||
|
// the OS_KEY environment variable can be used.
|
||||||
|
ClientKeyFile string `mapstructure:"key" required:"false"`
|
||||||
|
// the token (id) to use with token based authorization. Packer will use
|
||||||
|
// the environment variable OS_TOKEN, if set.
|
||||||
|
Token string `mapstructure:"token" required:"false"`
|
||||||
|
// The application credential name to use with application credential based
|
||||||
|
// authorization. Packer will use the environment variable
|
||||||
|
// OS_APPLICATION_CREDENTIAL_NAME, if set.
|
||||||
|
ApplicationCredentialName string `mapstructure:"application_credential_name" required:"false"`
|
||||||
|
// The application credential id to use with application credential based
|
||||||
|
// authorization. Packer will use the environment variable
|
||||||
|
// OS_APPLICATION_CREDENTIAL_ID, if set.
|
||||||
|
ApplicationCredentialID string `mapstructure:"application_credential_id" required:"false"`
|
||||||
|
// The application credential secret to use with application credential
|
||||||
|
// based authorization. Packer will use the environment variable
|
||||||
|
// OS_APPLICATION_CREDENTIAL_SECRET, if set.
|
||||||
|
ApplicationCredentialSecret string `mapstructure:"application_credential_secret" required:"false"`
|
||||||
|
// An entry in a `clouds.yaml` file. See the OpenStack os-client-config
|
||||||
|
// [documentation](https://docs.openstack.org/os-client-config/latest/user/configuration.html)
|
||||||
|
// for more information about `clouds.yaml` files. If omitted, the
|
||||||
|
// `OS_CLOUD` environment variable is used.
|
||||||
|
Cloud string `mapstructure:"cloud" required:"false"`
|
||||||
|
|
||||||
|
osClient *gophercloud.ProviderClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
|
if c.EndpointType != "internal" && c.EndpointType != "internalURL" &&
|
||||||
|
c.EndpointType != "admin" && c.EndpointType != "adminURL" &&
|
||||||
|
c.EndpointType != "public" && c.EndpointType != "publicURL" &&
|
||||||
|
c.EndpointType != "" {
|
||||||
|
return []error{fmt.Errorf("Invalid endpoint type provided")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy RackSpace stuff. We're keeping this around to keep things BC.
|
||||||
|
if c.Password == "" {
|
||||||
|
c.Password = os.Getenv("SDK_PASSWORD")
|
||||||
|
}
|
||||||
|
if c.Region == "" {
|
||||||
|
c.Region = os.Getenv("SDK_REGION")
|
||||||
|
}
|
||||||
|
if c.TenantName == "" {
|
||||||
|
c.TenantName = os.Getenv("SDK_PROJECT")
|
||||||
|
}
|
||||||
|
if c.Username == "" {
|
||||||
|
c.Username = os.Getenv("SDK_USERNAME")
|
||||||
|
}
|
||||||
|
// End RackSpace
|
||||||
|
|
||||||
|
if c.Cloud == "" {
|
||||||
|
c.Cloud = os.Getenv("OS_CLOUD")
|
||||||
|
}
|
||||||
|
if c.Region == "" {
|
||||||
|
c.Region = os.Getenv("OS_REGION_NAME")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.CACertFile == "" {
|
||||||
|
c.CACertFile = os.Getenv("OS_CACERT")
|
||||||
|
}
|
||||||
|
if c.ClientCertFile == "" {
|
||||||
|
c.ClientCertFile = os.Getenv("OS_CERT")
|
||||||
|
}
|
||||||
|
if c.ClientKeyFile == "" {
|
||||||
|
c.ClientKeyFile = os.Getenv("OS_KEY")
|
||||||
|
}
|
||||||
|
|
||||||
|
clientOpts := new(clientconfig.ClientOpts)
|
||||||
|
|
||||||
|
// If a cloud entry was given, base AuthOptions on a clouds.yaml file.
|
||||||
|
if c.Cloud != "" {
|
||||||
|
clientOpts.Cloud = c.Cloud
|
||||||
|
|
||||||
|
cloud, err := clientconfig.GetCloudFromYAML(clientOpts)
|
||||||
|
if err != nil {
|
||||||
|
return []error{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Region == "" && cloud.RegionName != "" {
|
||||||
|
c.Region = cloud.RegionName
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authInfo := &clientconfig.AuthInfo{
|
||||||
|
AuthURL: c.IdentityEndpoint,
|
||||||
|
DomainID: c.DomainID,
|
||||||
|
DomainName: c.DomainName,
|
||||||
|
Password: c.Password,
|
||||||
|
ProjectID: c.TenantID,
|
||||||
|
ProjectName: c.TenantName,
|
||||||
|
Token: c.Token,
|
||||||
|
Username: c.Username,
|
||||||
|
UserID: c.UserID,
|
||||||
|
}
|
||||||
|
clientOpts.AuthInfo = authInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
ao, err := clientconfig.AuthOptions(clientOpts)
|
||||||
|
if err != nil {
|
||||||
|
return []error{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we reauth as needed
|
||||||
|
ao.AllowReauth = true
|
||||||
|
|
||||||
|
// Override values if we have them in our config
|
||||||
|
overrides := []struct {
|
||||||
|
From, To *string
|
||||||
|
}{
|
||||||
|
{&c.Username, &ao.Username},
|
||||||
|
{&c.UserID, &ao.UserID},
|
||||||
|
{&c.Password, &ao.Password},
|
||||||
|
{&c.IdentityEndpoint, &ao.IdentityEndpoint},
|
||||||
|
{&c.TenantID, &ao.TenantID},
|
||||||
|
{&c.TenantName, &ao.TenantName},
|
||||||
|
{&c.DomainID, &ao.DomainID},
|
||||||
|
{&c.DomainName, &ao.DomainName},
|
||||||
|
{&c.Token, &ao.TokenID},
|
||||||
|
{&c.ApplicationCredentialName, &ao.ApplicationCredentialName},
|
||||||
|
{&c.ApplicationCredentialID, &ao.ApplicationCredentialID},
|
||||||
|
{&c.ApplicationCredentialSecret, &ao.ApplicationCredentialSecret},
|
||||||
|
}
|
||||||
|
for _, s := range overrides {
|
||||||
|
if *s.From != "" {
|
||||||
|
*s.To = *s.From
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the client itself
|
||||||
|
client, err := openstack.NewClient(ao.IdentityEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return []error{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
tls_config := &tls.Config{}
|
||||||
|
|
||||||
|
if c.CACertFile != "" {
|
||||||
|
caCert, err := ioutil.ReadFile(c.CACertFile)
|
||||||
|
if err != nil {
|
||||||
|
return []error{err}
|
||||||
|
}
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
|
tls_config.RootCAs = caCertPool
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have insecure set, then create a custom HTTP client that ignores
|
||||||
|
// SSL errors.
|
||||||
|
if c.Insecure {
|
||||||
|
tls_config.InsecureSkipVerify = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ClientCertFile != "" && c.ClientKeyFile != "" {
|
||||||
|
cert, err := tls.LoadX509KeyPair(c.ClientCertFile, c.ClientKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return []error{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
tls_config.Certificates = []tls.Certificate{cert}
|
||||||
|
}
|
||||||
|
|
||||||
|
transport := cleanhttp.DefaultTransport()
|
||||||
|
transport.TLSClientConfig = tls_config
|
||||||
|
client.HTTPClient.Transport = transport
|
||||||
|
|
||||||
|
// Auth
|
||||||
|
err = openstack.Authenticate(client, *ao)
|
||||||
|
if err != nil {
|
||||||
|
return []error{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.osClient = client
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) enableDebug(ui packersdk.Ui) {
|
||||||
|
c.osClient.HTTPClient = http.Client{
|
||||||
|
Transport: &DebugRoundTripper{
|
||||||
|
ui: ui,
|
||||||
|
rt: c.osClient.HTTPClient.Transport,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) computeV2Client() (*gophercloud.ServiceClient, error) {
|
||||||
|
return openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{
|
||||||
|
Region: c.Region,
|
||||||
|
Availability: c.getEndpointType(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) imageV2Client() (*gophercloud.ServiceClient, error) {
|
||||||
|
return openstack.NewImageServiceV2(c.osClient, gophercloud.EndpointOpts{
|
||||||
|
Region: c.Region,
|
||||||
|
Availability: c.getEndpointType(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) blockStorageV3Client() (*gophercloud.ServiceClient, error) {
|
||||||
|
return openstack.NewBlockStorageV3(c.osClient, gophercloud.EndpointOpts{
|
||||||
|
Region: c.Region,
|
||||||
|
Availability: c.getEndpointType(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) networkV2Client() (*gophercloud.ServiceClient, error) {
|
||||||
|
return openstack.NewNetworkV2(c.osClient, gophercloud.EndpointOpts{
|
||||||
|
Region: c.Region,
|
||||||
|
Availability: c.getEndpointType(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AccessConfig) getEndpointType() gophercloud.Availability {
|
||||||
|
if c.EndpointType == "internal" || c.EndpointType == "internalURL" {
|
||||||
|
return gophercloud.AvailabilityInternal
|
||||||
|
}
|
||||||
|
if c.EndpointType == "admin" || c.EndpointType == "adminURL" {
|
||||||
|
return gophercloud.AvailabilityAdmin
|
||||||
|
}
|
||||||
|
return gophercloud.AvailabilityPublic
|
||||||
|
}
|
||||||
|
|
||||||
|
type DebugRoundTripper struct {
|
||||||
|
ui packersdk.Ui
|
||||||
|
rt http.RoundTripper
|
||||||
|
numReauthAttempts int
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundTrip performs a round-trip HTTP request and logs relevant information about it.
|
||||||
|
func (drt *DebugRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||||
|
defer func() {
|
||||||
|
if request.Body != nil {
|
||||||
|
request.Body.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var response *http.Response
|
||||||
|
var err error
|
||||||
|
|
||||||
|
response, err = drt.rt.RoundTrip(request)
|
||||||
|
if response == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.StatusCode == http.StatusUnauthorized {
|
||||||
|
if drt.numReauthAttempts == 3 {
|
||||||
|
return response, fmt.Errorf("Tried to re-authenticate 3 times with no success.")
|
||||||
|
}
|
||||||
|
drt.numReauthAttempts++
|
||||||
|
}
|
||||||
|
|
||||||
|
drt.DebugMessage(fmt.Sprintf("Request %s %s %d", request.Method, request.URL, response.StatusCode))
|
||||||
|
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
body, _ := ioutil.ReadAll(io.TeeReader(response.Body, buf))
|
||||||
|
drt.DebugMessage(fmt.Sprintf("Response Error: %+v\n", string(body)))
|
||||||
|
bufWithClose := ioutil.NopCloser(buf)
|
||||||
|
response.Body = bufWithClose
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drt *DebugRoundTripper) DebugMessage(message string) {
|
||||||
|
drt.ui.Message(fmt.Sprintf("[DEBUG] %s", message))
|
||||||
|
}
|
51
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/artifact.go
generated
vendored
Normal file
51
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/artifact.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Artifact is an artifact implementation that contains built images.
|
||||||
|
type Artifact struct {
|
||||||
|
// ImageId of built image
|
||||||
|
ImageId string
|
||||||
|
|
||||||
|
// BuilderId is the unique ID for the builder that created this image
|
||||||
|
BuilderIdValue string
|
||||||
|
|
||||||
|
// OpenStack connection for performing API stuff.
|
||||||
|
Client *gophercloud.ServiceClient
|
||||||
|
|
||||||
|
// StateData should store data such as GeneratedData
|
||||||
|
// to be shared with post-processors
|
||||||
|
StateData map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Artifact) BuilderId() string {
|
||||||
|
return a.BuilderIdValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Artifact) Files() []string {
|
||||||
|
// We have no files
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Artifact) Id() string {
|
||||||
|
return a.ImageId
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Artifact) String() string {
|
||||||
|
return fmt.Sprintf("An image was created: %v", a.ImageId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Artifact) State(name string) interface{} {
|
||||||
|
return a.StateData[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Artifact) Destroy() error {
|
||||||
|
log.Printf("Destroying image: %s", a.ImageId)
|
||||||
|
return images.Delete(a.Client, a.ImageId).ExtractErr()
|
||||||
|
}
|
200
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/builder.go
generated
vendored
Normal file
200
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/builder.go
generated
vendored
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
//go:generate packer-sdc mapstructure-to-hcl2 -type Config,ImageFilter,ImageFilterOptions
|
||||||
|
|
||||||
|
// The openstack package contains a packersdk.Builder implementation that
|
||||||
|
// builds Images for openstack.
|
||||||
|
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl/v2/hcldec"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The unique ID for this builder
|
||||||
|
const BuilderId = "mitchellh.openstack"
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
common.PackerConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
|
AccessConfig `mapstructure:",squash"`
|
||||||
|
ImageConfig `mapstructure:",squash"`
|
||||||
|
RunConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
|
ctx interpolate.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
type Builder struct {
|
||||||
|
config Config
|
||||||
|
runner multistep.Runner
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() }
|
||||||
|
|
||||||
|
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
|
||||||
|
err := config.Decode(&b.config, &config.DecodeOpts{
|
||||||
|
PluginType: BuilderId,
|
||||||
|
Interpolate: true,
|
||||||
|
InterpolateContext: &b.config.ctx,
|
||||||
|
}, raws...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accumulate any errors
|
||||||
|
var errs *packersdk.MultiError
|
||||||
|
errs = packersdk.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
|
||||||
|
errs = packersdk.MultiErrorAppend(errs, b.config.ImageConfig.Prepare(&b.config.ctx)...)
|
||||||
|
errs = packersdk.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
|
||||||
|
|
||||||
|
if errs != nil && len(errs.Errors) > 0 {
|
||||||
|
return nil, nil, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.config.ImageConfig.ImageDiskFormat != "" && !b.config.RunConfig.UseBlockStorageVolume {
|
||||||
|
return nil, nil, fmt.Errorf("use_blockstorage_volume must be true if image_disk_format is specified.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default, instance name is same as image name
|
||||||
|
if b.config.InstanceName == "" {
|
||||||
|
b.config.InstanceName = b.config.ImageName
|
||||||
|
}
|
||||||
|
|
||||||
|
packersdk.LogSecretFilter.Set(b.config.Password)
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) {
|
||||||
|
if b.config.PackerDebug {
|
||||||
|
b.config.enableDebug(ui)
|
||||||
|
}
|
||||||
|
|
||||||
|
computeClient, err := b.config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
imageClient, err := b.config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error initializing image client: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the state bag and initial state for the steps
|
||||||
|
state := new(multistep.BasicStateBag)
|
||||||
|
state.Put("config", &b.config)
|
||||||
|
state.Put("hook", hook)
|
||||||
|
state.Put("ui", ui)
|
||||||
|
|
||||||
|
// Build the steps
|
||||||
|
steps := []multistep.Step{
|
||||||
|
&StepLoadFlavor{
|
||||||
|
Flavor: b.config.Flavor,
|
||||||
|
},
|
||||||
|
&StepKeyPair{
|
||||||
|
Debug: b.config.PackerDebug,
|
||||||
|
Comm: &b.config.Comm,
|
||||||
|
DebugKeyPath: fmt.Sprintf("os_%s.pem", b.config.PackerBuildName),
|
||||||
|
},
|
||||||
|
&StepSourceImageInfo{
|
||||||
|
SourceImage: b.config.RunConfig.SourceImage,
|
||||||
|
SourceImageName: b.config.RunConfig.SourceImageName,
|
||||||
|
ExternalSourceImageURL: b.config.RunConfig.ExternalSourceImageURL,
|
||||||
|
ExternalSourceImageFormat: b.config.RunConfig.ExternalSourceImageFormat,
|
||||||
|
ExternalSourceImageProperties: b.config.RunConfig.ExternalSourceImageProperties,
|
||||||
|
SourceImageOpts: b.config.RunConfig.sourceImageOpts,
|
||||||
|
SourceMostRecent: b.config.SourceImageFilters.MostRecent,
|
||||||
|
SourceProperties: b.config.SourceImageFilters.Filters.Properties,
|
||||||
|
},
|
||||||
|
&StepDiscoverNetwork{
|
||||||
|
Networks: b.config.Networks,
|
||||||
|
NetworkDiscoveryCIDRs: b.config.NetworkDiscoveryCIDRs,
|
||||||
|
Ports: b.config.Ports,
|
||||||
|
},
|
||||||
|
&StepCreateVolume{
|
||||||
|
UseBlockStorageVolume: b.config.UseBlockStorageVolume,
|
||||||
|
VolumeName: b.config.VolumeName,
|
||||||
|
VolumeType: b.config.VolumeType,
|
||||||
|
VolumeAvailabilityZone: b.config.VolumeAvailabilityZone,
|
||||||
|
},
|
||||||
|
&StepRunSourceServer{
|
||||||
|
Name: b.config.InstanceName,
|
||||||
|
SecurityGroups: b.config.SecurityGroups,
|
||||||
|
AvailabilityZone: b.config.AvailabilityZone,
|
||||||
|
UserData: b.config.UserData,
|
||||||
|
UserDataFile: b.config.UserDataFile,
|
||||||
|
ConfigDrive: b.config.ConfigDrive,
|
||||||
|
InstanceMetadata: b.config.InstanceMetadata,
|
||||||
|
UseBlockStorageVolume: b.config.UseBlockStorageVolume,
|
||||||
|
ForceDelete: b.config.ForceDelete,
|
||||||
|
},
|
||||||
|
&StepGetPassword{
|
||||||
|
Debug: b.config.PackerDebug,
|
||||||
|
Comm: &b.config.RunConfig.Comm,
|
||||||
|
},
|
||||||
|
&StepWaitForRackConnect{
|
||||||
|
Wait: b.config.RackconnectWait,
|
||||||
|
},
|
||||||
|
&StepAllocateIp{
|
||||||
|
FloatingIPNetwork: b.config.FloatingIPNetwork,
|
||||||
|
FloatingIP: b.config.FloatingIP,
|
||||||
|
ReuseIPs: b.config.ReuseIPs,
|
||||||
|
InstanceFloatingIPNet: b.config.InstanceFloatingIPNet,
|
||||||
|
},
|
||||||
|
&communicator.StepConnect{
|
||||||
|
Config: &b.config.RunConfig.Comm,
|
||||||
|
Host: CommHost(
|
||||||
|
b.config.RunConfig.Comm.Host(),
|
||||||
|
computeClient,
|
||||||
|
b.config.SSHInterface,
|
||||||
|
b.config.SSHIPVersion),
|
||||||
|
SSHConfig: b.config.RunConfig.Comm.SSHConfigFunc(),
|
||||||
|
},
|
||||||
|
&commonsteps.StepProvision{},
|
||||||
|
&commonsteps.StepCleanupTempKeys{
|
||||||
|
Comm: &b.config.RunConfig.Comm,
|
||||||
|
},
|
||||||
|
&StepStopServer{},
|
||||||
|
&StepDetachVolume{
|
||||||
|
UseBlockStorageVolume: b.config.UseBlockStorageVolume,
|
||||||
|
},
|
||||||
|
&stepCreateImage{
|
||||||
|
UseBlockStorageVolume: b.config.UseBlockStorageVolume,
|
||||||
|
},
|
||||||
|
&stepUpdateImageTags{},
|
||||||
|
&stepUpdateImageVisibility{},
|
||||||
|
&stepAddImageMembers{},
|
||||||
|
&stepUpdateImageMinDisk{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run!
|
||||||
|
b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui)
|
||||||
|
b.runner.Run(ctx, state)
|
||||||
|
|
||||||
|
// If there was an error, return that
|
||||||
|
if rawErr, ok := state.GetOk("error"); ok {
|
||||||
|
return nil, rawErr.(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no images, then just return
|
||||||
|
if _, ok := state.GetOk("image"); !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the artifact and return it
|
||||||
|
artifact := &Artifact{
|
||||||
|
ImageId: state.Get("image").(string),
|
||||||
|
BuilderIdValue: BuilderId,
|
||||||
|
Client: imageClient,
|
||||||
|
StateData: map[string]interface{}{"generated_data": state.Get("generated_data")},
|
||||||
|
}
|
||||||
|
|
||||||
|
return artifact, nil
|
||||||
|
}
|
322
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/builder.hcl2spec.go
generated
vendored
Normal file
322
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/builder.hcl2spec.go
generated
vendored
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
"github.com/hashicorp/hcl/v2/hcldec"
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FlatConfig is an auto-generated flat version of Config.
|
||||||
|
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||||
|
type FlatConfig struct {
|
||||||
|
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
|
||||||
|
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
|
||||||
|
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
|
||||||
|
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
|
||||||
|
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
|
||||||
|
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
|
||||||
|
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
|
||||||
|
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
|
||||||
|
Username *string `mapstructure:"username" required:"true" cty:"username" hcl:"username"`
|
||||||
|
UserID *string `mapstructure:"user_id" cty:"user_id" hcl:"user_id"`
|
||||||
|
Password *string `mapstructure:"password" required:"true" cty:"password" hcl:"password"`
|
||||||
|
IdentityEndpoint *string `mapstructure:"identity_endpoint" required:"true" cty:"identity_endpoint" hcl:"identity_endpoint"`
|
||||||
|
TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"`
|
||||||
|
TenantName *string `mapstructure:"tenant_name" cty:"tenant_name" hcl:"tenant_name"`
|
||||||
|
DomainID *string `mapstructure:"domain_id" cty:"domain_id" hcl:"domain_id"`
|
||||||
|
DomainName *string `mapstructure:"domain_name" required:"false" cty:"domain_name" hcl:"domain_name"`
|
||||||
|
Insecure *bool `mapstructure:"insecure" required:"false" cty:"insecure" hcl:"insecure"`
|
||||||
|
Region *string `mapstructure:"region" required:"false" cty:"region" hcl:"region"`
|
||||||
|
EndpointType *string `mapstructure:"endpoint_type" required:"false" cty:"endpoint_type" hcl:"endpoint_type"`
|
||||||
|
CACertFile *string `mapstructure:"cacert" required:"false" cty:"cacert" hcl:"cacert"`
|
||||||
|
ClientCertFile *string `mapstructure:"cert" required:"false" cty:"cert" hcl:"cert"`
|
||||||
|
ClientKeyFile *string `mapstructure:"key" required:"false" cty:"key" hcl:"key"`
|
||||||
|
Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"`
|
||||||
|
ApplicationCredentialName *string `mapstructure:"application_credential_name" required:"false" cty:"application_credential_name" hcl:"application_credential_name"`
|
||||||
|
ApplicationCredentialID *string `mapstructure:"application_credential_id" required:"false" cty:"application_credential_id" hcl:"application_credential_id"`
|
||||||
|
ApplicationCredentialSecret *string `mapstructure:"application_credential_secret" required:"false" cty:"application_credential_secret" hcl:"application_credential_secret"`
|
||||||
|
Cloud *string `mapstructure:"cloud" required:"false" cty:"cloud" hcl:"cloud"`
|
||||||
|
ImageName *string `mapstructure:"image_name" required:"true" cty:"image_name" hcl:"image_name"`
|
||||||
|
ImageMetadata map[string]string `mapstructure:"metadata" required:"false" cty:"metadata" hcl:"metadata"`
|
||||||
|
ImageVisibility *images.ImageVisibility `mapstructure:"image_visibility" required:"false" cty:"image_visibility" hcl:"image_visibility"`
|
||||||
|
ImageMembers []string `mapstructure:"image_members" required:"false" cty:"image_members" hcl:"image_members"`
|
||||||
|
ImageAutoAcceptMembers *bool `mapstructure:"image_auto_accept_members" required:"false" cty:"image_auto_accept_members" hcl:"image_auto_accept_members"`
|
||||||
|
ImageDiskFormat *string `mapstructure:"image_disk_format" required:"false" cty:"image_disk_format" hcl:"image_disk_format"`
|
||||||
|
ImageTags []string `mapstructure:"image_tags" required:"false" cty:"image_tags" hcl:"image_tags"`
|
||||||
|
ImageMinDisk *int `mapstructure:"image_min_disk" required:"false" cty:"image_min_disk" hcl:"image_min_disk"`
|
||||||
|
SkipCreateImage *bool `mapstructure:"skip_create_image" required:"false" cty:"skip_create_image" hcl:"skip_create_image"`
|
||||||
|
Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"`
|
||||||
|
PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"`
|
||||||
|
SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"`
|
||||||
|
SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"`
|
||||||
|
SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"`
|
||||||
|
SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"`
|
||||||
|
SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"`
|
||||||
|
SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"`
|
||||||
|
SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"`
|
||||||
|
SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"`
|
||||||
|
SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"`
|
||||||
|
SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"`
|
||||||
|
SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"`
|
||||||
|
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
|
||||||
|
SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"`
|
||||||
|
SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"`
|
||||||
|
SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"`
|
||||||
|
SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"`
|
||||||
|
SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"`
|
||||||
|
SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"`
|
||||||
|
SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"`
|
||||||
|
SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"`
|
||||||
|
SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"`
|
||||||
|
SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"`
|
||||||
|
SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"`
|
||||||
|
SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"`
|
||||||
|
SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"`
|
||||||
|
SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"`
|
||||||
|
SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"`
|
||||||
|
SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"`
|
||||||
|
SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"`
|
||||||
|
SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"`
|
||||||
|
SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"`
|
||||||
|
SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"`
|
||||||
|
SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"`
|
||||||
|
SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"`
|
||||||
|
SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"`
|
||||||
|
SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"`
|
||||||
|
SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"`
|
||||||
|
SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"`
|
||||||
|
WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"`
|
||||||
|
WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"`
|
||||||
|
WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"`
|
||||||
|
WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"`
|
||||||
|
WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"`
|
||||||
|
WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"`
|
||||||
|
WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"`
|
||||||
|
WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"`
|
||||||
|
WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"`
|
||||||
|
SSHInterface *string `mapstructure:"ssh_interface" required:"false" cty:"ssh_interface" hcl:"ssh_interface"`
|
||||||
|
SSHIPVersion *string `mapstructure:"ssh_ip_version" required:"false" cty:"ssh_ip_version" hcl:"ssh_ip_version"`
|
||||||
|
SourceImage *string `mapstructure:"source_image" required:"true" cty:"source_image" hcl:"source_image"`
|
||||||
|
SourceImageName *string `mapstructure:"source_image_name" required:"true" cty:"source_image_name" hcl:"source_image_name"`
|
||||||
|
ExternalSourceImageURL *string `mapstructure:"external_source_image_url" required:"true" cty:"external_source_image_url" hcl:"external_source_image_url"`
|
||||||
|
ExternalSourceImageFormat *string `mapstructure:"external_source_image_format" required:"false" cty:"external_source_image_format" hcl:"external_source_image_format"`
|
||||||
|
ExternalSourceImageProperties map[string]string `mapstructure:"external_source_image_properties" required:"false" cty:"external_source_image_properties" hcl:"external_source_image_properties"`
|
||||||
|
SourceImageFilters *FlatImageFilter `mapstructure:"source_image_filter" required:"true" cty:"source_image_filter" hcl:"source_image_filter"`
|
||||||
|
Flavor *string `mapstructure:"flavor" required:"true" cty:"flavor" hcl:"flavor"`
|
||||||
|
AvailabilityZone *string `mapstructure:"availability_zone" required:"false" cty:"availability_zone" hcl:"availability_zone"`
|
||||||
|
RackconnectWait *bool `mapstructure:"rackconnect_wait" required:"false" cty:"rackconnect_wait" hcl:"rackconnect_wait"`
|
||||||
|
FloatingIPNetwork *string `mapstructure:"floating_ip_network" required:"false" cty:"floating_ip_network" hcl:"floating_ip_network"`
|
||||||
|
InstanceFloatingIPNet *string `mapstructure:"instance_floating_ip_net" required:"false" cty:"instance_floating_ip_net" hcl:"instance_floating_ip_net"`
|
||||||
|
FloatingIP *string `mapstructure:"floating_ip" required:"false" cty:"floating_ip" hcl:"floating_ip"`
|
||||||
|
ReuseIPs *bool `mapstructure:"reuse_ips" required:"false" cty:"reuse_ips" hcl:"reuse_ips"`
|
||||||
|
SecurityGroups []string `mapstructure:"security_groups" required:"false" cty:"security_groups" hcl:"security_groups"`
|
||||||
|
Networks []string `mapstructure:"networks" required:"false" cty:"networks" hcl:"networks"`
|
||||||
|
Ports []string `mapstructure:"ports" required:"false" cty:"ports" hcl:"ports"`
|
||||||
|
NetworkDiscoveryCIDRs []string `mapstructure:"network_discovery_cidrs" required:"false" cty:"network_discovery_cidrs" hcl:"network_discovery_cidrs"`
|
||||||
|
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data" hcl:"user_data"`
|
||||||
|
UserDataFile *string `mapstructure:"user_data_file" required:"false" cty:"user_data_file" hcl:"user_data_file"`
|
||||||
|
InstanceName *string `mapstructure:"instance_name" required:"false" cty:"instance_name" hcl:"instance_name"`
|
||||||
|
InstanceMetadata map[string]string `mapstructure:"instance_metadata" required:"false" cty:"instance_metadata" hcl:"instance_metadata"`
|
||||||
|
ForceDelete *bool `mapstructure:"force_delete" required:"false" cty:"force_delete" hcl:"force_delete"`
|
||||||
|
ConfigDrive *bool `mapstructure:"config_drive" required:"false" cty:"config_drive" hcl:"config_drive"`
|
||||||
|
FloatingIPPool *string `mapstructure:"floating_ip_pool" required:"false" cty:"floating_ip_pool" hcl:"floating_ip_pool"`
|
||||||
|
UseBlockStorageVolume *bool `mapstructure:"use_blockstorage_volume" required:"false" cty:"use_blockstorage_volume" hcl:"use_blockstorage_volume"`
|
||||||
|
VolumeName *string `mapstructure:"volume_name" required:"false" cty:"volume_name" hcl:"volume_name"`
|
||||||
|
VolumeType *string `mapstructure:"volume_type" required:"false" cty:"volume_type" hcl:"volume_type"`
|
||||||
|
VolumeSize *int `mapstructure:"volume_size" required:"false" cty:"volume_size" hcl:"volume_size"`
|
||||||
|
VolumeAvailabilityZone *string `mapstructure:"volume_availability_zone" required:"false" cty:"volume_availability_zone" hcl:"volume_availability_zone"`
|
||||||
|
OpenstackProvider *string `mapstructure:"openstack_provider" cty:"openstack_provider" hcl:"openstack_provider"`
|
||||||
|
UseFloatingIp *bool `mapstructure:"use_floating_ip" required:"false" cty:"use_floating_ip" hcl:"use_floating_ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlatMapstructure returns a new FlatConfig.
|
||||||
|
// FlatConfig is an auto-generated flat version of Config.
|
||||||
|
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||||
|
func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||||
|
return new(FlatConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HCL2Spec returns the hcl spec of a Config.
|
||||||
|
// This spec is used by HCL to read the fields of Config.
|
||||||
|
// The decoded values from this spec will then be applied to a FlatConfig.
|
||||||
|
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||||
|
s := map[string]hcldec.Spec{
|
||||||
|
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
|
||||||
|
"packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false},
|
||||||
|
"packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false},
|
||||||
|
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
|
||||||
|
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
|
||||||
|
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
|
||||||
|
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
|
||||||
|
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
|
||||||
|
"username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false},
|
||||||
|
"user_id": &hcldec.AttrSpec{Name: "user_id", Type: cty.String, Required: false},
|
||||||
|
"password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false},
|
||||||
|
"identity_endpoint": &hcldec.AttrSpec{Name: "identity_endpoint", Type: cty.String, Required: false},
|
||||||
|
"tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false},
|
||||||
|
"tenant_name": &hcldec.AttrSpec{Name: "tenant_name", Type: cty.String, Required: false},
|
||||||
|
"domain_id": &hcldec.AttrSpec{Name: "domain_id", Type: cty.String, Required: false},
|
||||||
|
"domain_name": &hcldec.AttrSpec{Name: "domain_name", Type: cty.String, Required: false},
|
||||||
|
"insecure": &hcldec.AttrSpec{Name: "insecure", Type: cty.Bool, Required: false},
|
||||||
|
"region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false},
|
||||||
|
"endpoint_type": &hcldec.AttrSpec{Name: "endpoint_type", Type: cty.String, Required: false},
|
||||||
|
"cacert": &hcldec.AttrSpec{Name: "cacert", Type: cty.String, Required: false},
|
||||||
|
"cert": &hcldec.AttrSpec{Name: "cert", Type: cty.String, Required: false},
|
||||||
|
"key": &hcldec.AttrSpec{Name: "key", Type: cty.String, Required: false},
|
||||||
|
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
|
||||||
|
"application_credential_name": &hcldec.AttrSpec{Name: "application_credential_name", Type: cty.String, Required: false},
|
||||||
|
"application_credential_id": &hcldec.AttrSpec{Name: "application_credential_id", Type: cty.String, Required: false},
|
||||||
|
"application_credential_secret": &hcldec.AttrSpec{Name: "application_credential_secret", Type: cty.String, Required: false},
|
||||||
|
"cloud": &hcldec.AttrSpec{Name: "cloud", Type: cty.String, Required: false},
|
||||||
|
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
|
||||||
|
"metadata": &hcldec.AttrSpec{Name: "metadata", Type: cty.Map(cty.String), Required: false},
|
||||||
|
"image_visibility": &hcldec.AttrSpec{Name: "image_visibility", Type: cty.String, Required: false},
|
||||||
|
"image_members": &hcldec.AttrSpec{Name: "image_members", Type: cty.List(cty.String), Required: false},
|
||||||
|
"image_auto_accept_members": &hcldec.AttrSpec{Name: "image_auto_accept_members", Type: cty.Bool, Required: false},
|
||||||
|
"image_disk_format": &hcldec.AttrSpec{Name: "image_disk_format", Type: cty.String, Required: false},
|
||||||
|
"image_tags": &hcldec.AttrSpec{Name: "image_tags", Type: cty.List(cty.String), Required: false},
|
||||||
|
"image_min_disk": &hcldec.AttrSpec{Name: "image_min_disk", Type: cty.Number, Required: false},
|
||||||
|
"skip_create_image": &hcldec.AttrSpec{Name: "skip_create_image", Type: cty.Bool, Required: false},
|
||||||
|
"communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false},
|
||||||
|
"pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false},
|
||||||
|
"ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false},
|
||||||
|
"ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false},
|
||||||
|
"ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false},
|
||||||
|
"ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false},
|
||||||
|
"ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false},
|
||||||
|
"temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false},
|
||||||
|
"temporary_key_pair_type": &hcldec.AttrSpec{Name: "temporary_key_pair_type", Type: cty.String, Required: false},
|
||||||
|
"temporary_key_pair_bits": &hcldec.AttrSpec{Name: "temporary_key_pair_bits", Type: cty.Number, Required: false},
|
||||||
|
"ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false},
|
||||||
|
"ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false},
|
||||||
|
"ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false},
|
||||||
|
"ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false},
|
||||||
|
"ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false},
|
||||||
|
"ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false},
|
||||||
|
"ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false},
|
||||||
|
"ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false},
|
||||||
|
"ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false},
|
||||||
|
"ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false},
|
||||||
|
"ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false},
|
||||||
|
"ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false},
|
||||||
|
"ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false},
|
||||||
|
"ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false},
|
||||||
|
"ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false},
|
||||||
|
"ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false},
|
||||||
|
"ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false},
|
||||||
|
"ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false},
|
||||||
|
"ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false},
|
||||||
|
"ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false},
|
||||||
|
"ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false},
|
||||||
|
"ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false},
|
||||||
|
"ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false},
|
||||||
|
"ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false},
|
||||||
|
"ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false},
|
||||||
|
"ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false},
|
||||||
|
"ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false},
|
||||||
|
"ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false},
|
||||||
|
"ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false},
|
||||||
|
"ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false},
|
||||||
|
"winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false},
|
||||||
|
"winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false},
|
||||||
|
"winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false},
|
||||||
|
"winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false},
|
||||||
|
"winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false},
|
||||||
|
"winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false},
|
||||||
|
"winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false},
|
||||||
|
"winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false},
|
||||||
|
"winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false},
|
||||||
|
"ssh_interface": &hcldec.AttrSpec{Name: "ssh_interface", Type: cty.String, Required: false},
|
||||||
|
"ssh_ip_version": &hcldec.AttrSpec{Name: "ssh_ip_version", Type: cty.String, Required: false},
|
||||||
|
"source_image": &hcldec.AttrSpec{Name: "source_image", Type: cty.String, Required: false},
|
||||||
|
"source_image_name": &hcldec.AttrSpec{Name: "source_image_name", Type: cty.String, Required: false},
|
||||||
|
"external_source_image_url": &hcldec.AttrSpec{Name: "external_source_image_url", Type: cty.String, Required: false},
|
||||||
|
"external_source_image_format": &hcldec.AttrSpec{Name: "external_source_image_format", Type: cty.String, Required: false},
|
||||||
|
"external_source_image_properties": &hcldec.AttrSpec{Name: "external_source_image_properties", Type: cty.Map(cty.String), Required: false},
|
||||||
|
"source_image_filter": &hcldec.BlockSpec{TypeName: "source_image_filter", Nested: hcldec.ObjectSpec((*FlatImageFilter)(nil).HCL2Spec())},
|
||||||
|
"flavor": &hcldec.AttrSpec{Name: "flavor", Type: cty.String, Required: false},
|
||||||
|
"availability_zone": &hcldec.AttrSpec{Name: "availability_zone", Type: cty.String, Required: false},
|
||||||
|
"rackconnect_wait": &hcldec.AttrSpec{Name: "rackconnect_wait", Type: cty.Bool, Required: false},
|
||||||
|
"floating_ip_network": &hcldec.AttrSpec{Name: "floating_ip_network", Type: cty.String, Required: false},
|
||||||
|
"instance_floating_ip_net": &hcldec.AttrSpec{Name: "instance_floating_ip_net", Type: cty.String, Required: false},
|
||||||
|
"floating_ip": &hcldec.AttrSpec{Name: "floating_ip", Type: cty.String, Required: false},
|
||||||
|
"reuse_ips": &hcldec.AttrSpec{Name: "reuse_ips", Type: cty.Bool, Required: false},
|
||||||
|
"security_groups": &hcldec.AttrSpec{Name: "security_groups", Type: cty.List(cty.String), Required: false},
|
||||||
|
"networks": &hcldec.AttrSpec{Name: "networks", Type: cty.List(cty.String), Required: false},
|
||||||
|
"ports": &hcldec.AttrSpec{Name: "ports", Type: cty.List(cty.String), Required: false},
|
||||||
|
"network_discovery_cidrs": &hcldec.AttrSpec{Name: "network_discovery_cidrs", Type: cty.List(cty.String), Required: false},
|
||||||
|
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
|
||||||
|
"user_data_file": &hcldec.AttrSpec{Name: "user_data_file", Type: cty.String, Required: false},
|
||||||
|
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
|
||||||
|
"instance_metadata": &hcldec.AttrSpec{Name: "instance_metadata", Type: cty.Map(cty.String), Required: false},
|
||||||
|
"force_delete": &hcldec.AttrSpec{Name: "force_delete", Type: cty.Bool, Required: false},
|
||||||
|
"config_drive": &hcldec.AttrSpec{Name: "config_drive", Type: cty.Bool, Required: false},
|
||||||
|
"floating_ip_pool": &hcldec.AttrSpec{Name: "floating_ip_pool", Type: cty.String, Required: false},
|
||||||
|
"use_blockstorage_volume": &hcldec.AttrSpec{Name: "use_blockstorage_volume", Type: cty.Bool, Required: false},
|
||||||
|
"volume_name": &hcldec.AttrSpec{Name: "volume_name", Type: cty.String, Required: false},
|
||||||
|
"volume_type": &hcldec.AttrSpec{Name: "volume_type", Type: cty.String, Required: false},
|
||||||
|
"volume_size": &hcldec.AttrSpec{Name: "volume_size", Type: cty.Number, Required: false},
|
||||||
|
"volume_availability_zone": &hcldec.AttrSpec{Name: "volume_availability_zone", Type: cty.String, Required: false},
|
||||||
|
"openstack_provider": &hcldec.AttrSpec{Name: "openstack_provider", Type: cty.String, Required: false},
|
||||||
|
"use_floating_ip": &hcldec.AttrSpec{Name: "use_floating_ip", Type: cty.Bool, Required: false},
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlatImageFilter is an auto-generated flat version of ImageFilter.
|
||||||
|
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||||
|
type FlatImageFilter struct {
|
||||||
|
Filters *FlatImageFilterOptions `mapstructure:"filters" required:"false" cty:"filters" hcl:"filters"`
|
||||||
|
MostRecent *bool `mapstructure:"most_recent" required:"false" cty:"most_recent" hcl:"most_recent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlatMapstructure returns a new FlatImageFilter.
|
||||||
|
// FlatImageFilter is an auto-generated flat version of ImageFilter.
|
||||||
|
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||||
|
func (*ImageFilter) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||||
|
return new(FlatImageFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HCL2Spec returns the hcl spec of a ImageFilter.
|
||||||
|
// This spec is used by HCL to read the fields of ImageFilter.
|
||||||
|
// The decoded values from this spec will then be applied to a FlatImageFilter.
|
||||||
|
func (*FlatImageFilter) HCL2Spec() map[string]hcldec.Spec {
|
||||||
|
s := map[string]hcldec.Spec{
|
||||||
|
"filters": &hcldec.BlockSpec{TypeName: "filters", Nested: hcldec.ObjectSpec((*FlatImageFilterOptions)(nil).HCL2Spec())},
|
||||||
|
"most_recent": &hcldec.AttrSpec{Name: "most_recent", Type: cty.Bool, Required: false},
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlatImageFilterOptions is an auto-generated flat version of ImageFilterOptions.
|
||||||
|
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||||
|
type FlatImageFilterOptions struct {
|
||||||
|
Name *string `mapstructure:"name" cty:"name" hcl:"name"`
|
||||||
|
Owner *string `mapstructure:"owner" cty:"owner" hcl:"owner"`
|
||||||
|
Tags []string `mapstructure:"tags" cty:"tags" hcl:"tags"`
|
||||||
|
Visibility *string `mapstructure:"visibility" cty:"visibility" hcl:"visibility"`
|
||||||
|
Properties map[string]string `mapstructure:"properties" cty:"properties" hcl:"properties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlatMapstructure returns a new FlatImageFilterOptions.
|
||||||
|
// FlatImageFilterOptions is an auto-generated flat version of ImageFilterOptions.
|
||||||
|
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||||
|
func (*ImageFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||||
|
return new(FlatImageFilterOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HCL2Spec returns the hcl spec of a ImageFilterOptions.
|
||||||
|
// This spec is used by HCL to read the fields of ImageFilterOptions.
|
||||||
|
// The decoded values from this spec will then be applied to a FlatImageFilterOptions.
|
||||||
|
func (*FlatImageFilterOptions) HCL2Spec() map[string]hcldec.Spec {
|
||||||
|
s := map[string]hcldec.Spec{
|
||||||
|
"name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false},
|
||||||
|
"owner": &hcldec.AttrSpec{Name: "owner", Type: cty.String, Required: false},
|
||||||
|
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.List(cty.String), Required: false},
|
||||||
|
"visibility": &hcldec.AttrSpec{Name: "visibility", Type: cty.String, Required: false},
|
||||||
|
"properties": &hcldec.AttrSpec{Name: "properties", Type: cty.Map(cty.String), Required: false},
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
83
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/image_config.go
generated
vendored
Normal file
83
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/image_config.go
generated
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
//go:generate packer-sdc struct-markdown
|
||||||
|
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
imageservice "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImageConfig is for common configuration related to creating Images.
|
||||||
|
type ImageConfig struct {
|
||||||
|
// The name of the resulting image.
|
||||||
|
ImageName string `mapstructure:"image_name" required:"true"`
|
||||||
|
// Glance metadata that will be applied to the image.
|
||||||
|
ImageMetadata map[string]string `mapstructure:"metadata" required:"false"`
|
||||||
|
// One of "public", "private", "shared", or "community".
|
||||||
|
ImageVisibility imageservice.ImageVisibility `mapstructure:"image_visibility" required:"false"`
|
||||||
|
// List of members to add to the image after creation. An image member is
|
||||||
|
// usually a project (also called the "tenant") with whom the image is
|
||||||
|
// shared.
|
||||||
|
ImageMembers []string `mapstructure:"image_members" required:"false"`
|
||||||
|
// When true, perform the image accept so the members can see the image in their
|
||||||
|
// project. This requires a user with priveleges both in the build project and
|
||||||
|
// in the members provided. Defaults to false.
|
||||||
|
ImageAutoAcceptMembers bool `mapstructure:"image_auto_accept_members" required:"false"`
|
||||||
|
// Disk format of the resulting image. This option works if
|
||||||
|
// use_blockstorage_volume is true.
|
||||||
|
ImageDiskFormat string `mapstructure:"image_disk_format" required:"false"`
|
||||||
|
// List of tags to add to the image after creation.
|
||||||
|
ImageTags []string `mapstructure:"image_tags" required:"false"`
|
||||||
|
// Minimum disk size needed to boot image, in gigabytes.
|
||||||
|
ImageMinDisk int `mapstructure:"image_min_disk" required:"false"`
|
||||||
|
// Skip creating the image. Useful for setting to `true` during a build test stage. Defaults to `false`.
|
||||||
|
SkipCreateImage bool `mapstructure:"skip_create_image" required:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ImageConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
|
errs := make([]error, 0)
|
||||||
|
if c.ImageName == "" {
|
||||||
|
errs = append(errs, fmt.Errorf("An image_name must be specified"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default, OpenStack seems to create the image with an image_type of
|
||||||
|
// "snapshot", since it came from snapshotting a VM. A "snapshot" looks
|
||||||
|
// slightly different in the OpenStack UI and OpenStack won't show
|
||||||
|
// "snapshot" images as a choice in the list of images to boot from for a
|
||||||
|
// new instance. See https://github.com/hashicorp/packer/issues/3038
|
||||||
|
if c.ImageMetadata == nil {
|
||||||
|
c.ImageMetadata = map[string]string{"image_type": "image"}
|
||||||
|
} else if c.ImageMetadata["image_type"] == "" {
|
||||||
|
c.ImageMetadata["image_type"] = "image"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageVisibility values
|
||||||
|
// https://wiki.openstack.org/wiki/Glance-v2-community-image-visibility-design
|
||||||
|
if c.ImageVisibility != "" {
|
||||||
|
validVals := []imageservice.ImageVisibility{"public", "private", "shared", "community"}
|
||||||
|
valid := false
|
||||||
|
for _, val := range validVals {
|
||||||
|
if strings.EqualFold(string(c.ImageVisibility), string(val)) {
|
||||||
|
valid = true
|
||||||
|
c.ImageVisibility = val
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
errs = append(errs, fmt.Errorf("Unknown visibility value %s", c.ImageVisibility))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.ImageMinDisk < 0 {
|
||||||
|
errs = append(errs, fmt.Errorf("An image min disk size must be greater than or equal to 0"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
180
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/networks.go
generated
vendored
Normal file
180
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/networks.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CheckFloatingIP gets a floating IP by its ID and checks if it is already
|
||||||
|
// associated with any internal interface.
|
||||||
|
// It returns floating IP if it can be used.
|
||||||
|
func CheckFloatingIP(client *gophercloud.ServiceClient, id string) (*floatingips.FloatingIP, error) {
|
||||||
|
floatingIP, err := floatingips.Get(client, id).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if floatingIP.PortID != "" {
|
||||||
|
return nil, fmt.Errorf("provided floating IP '%s' is already associated with port '%s'",
|
||||||
|
id, floatingIP.PortID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return floatingIP, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindFreeFloatingIP returns free unassociated floating IP.
|
||||||
|
// It will return first floating IP if there are many.
|
||||||
|
func FindFreeFloatingIP(client *gophercloud.ServiceClient) (*floatingips.FloatingIP, error) {
|
||||||
|
var freeFloatingIP *floatingips.FloatingIP
|
||||||
|
|
||||||
|
pager := floatingips.List(client, floatingips.ListOpts{
|
||||||
|
Status: "DOWN",
|
||||||
|
})
|
||||||
|
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
candidates, err := floatingips.ExtractFloatingIPs(page)
|
||||||
|
if err != nil {
|
||||||
|
return false, err // stop and throw error out
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, candidate := range candidates {
|
||||||
|
if candidate.PortID != "" {
|
||||||
|
continue // this floating IP is associated with port, move to next in list
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floating IP is able to be allocated.
|
||||||
|
freeFloatingIP = &candidate
|
||||||
|
return false, nil // stop iterating over pages
|
||||||
|
}
|
||||||
|
return true, nil // try the next page
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if freeFloatingIP == nil {
|
||||||
|
return nil, fmt.Errorf("no free floating IPs found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return freeFloatingIP, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstancePortID returns internal port of the instance that can be used for
|
||||||
|
// the association of a floating IP.
|
||||||
|
// It will return an ID of a first port if there are many.
|
||||||
|
func GetInstancePortID(client *gophercloud.ServiceClient, id string, instance_float_net string) (string, error) {
|
||||||
|
|
||||||
|
selected_interface := 0
|
||||||
|
|
||||||
|
interfacesPage, err := attachinterfaces.List(client, id).AllPages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
interfaces, err := attachinterfaces.ExtractInterfaces(interfacesPage)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(interfaces) == 0 {
|
||||||
|
return "", fmt.Errorf("instance '%s' has no interfaces", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(interfaces); i++ {
|
||||||
|
log.Printf("Instance interface: %v: %+v\n", i, interfaces[i])
|
||||||
|
if interfaces[i].NetID == instance_float_net {
|
||||||
|
log.Printf("Found preferred interface: %v\n", i)
|
||||||
|
selected_interface = i
|
||||||
|
log.Printf("Using interface value: %v", selected_interface)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return interfaces[selected_interface].PortID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckFloatingIPNetwork checks provided network reference and returns a valid
|
||||||
|
// Networking service ID.
|
||||||
|
func CheckFloatingIPNetwork(client *gophercloud.ServiceClient, networkRef string) (string, error) {
|
||||||
|
if _, err := uuid.Parse(networkRef); err != nil {
|
||||||
|
return GetFloatingIPNetworkIDByName(client, networkRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
return networkRef, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalNetwork is a network with external router.
|
||||||
|
type ExternalNetwork struct {
|
||||||
|
networks.Network
|
||||||
|
external.NetworkExternalExt
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFloatingIPNetworkIDByName searches for the external network ID by the provided name.
|
||||||
|
func GetFloatingIPNetworkIDByName(client *gophercloud.ServiceClient, networkName string) (string, error) {
|
||||||
|
var externalNetworks []ExternalNetwork
|
||||||
|
|
||||||
|
allPages, err := networks.List(client, networks.ListOpts{
|
||||||
|
Name: networkName,
|
||||||
|
}).AllPages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := networks.ExtractNetworksInto(allPages, &externalNetworks); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(externalNetworks) == 0 {
|
||||||
|
return "", fmt.Errorf("can't find external network %s", networkName)
|
||||||
|
}
|
||||||
|
// Check and return the first external network.
|
||||||
|
if !externalNetworks[0].External {
|
||||||
|
return "", fmt.Errorf("network %s is not external", networkName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return externalNetworks[0].ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscoverProvisioningNetwork finds the first network whose subnet matches the given network ranges.
|
||||||
|
func DiscoverProvisioningNetwork(client *gophercloud.ServiceClient, cidrs []string) (string, error) {
|
||||||
|
allPages, err := subnets.List(client, subnets.ListOpts{}).AllPages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
allSubnets, err := subnets.ExtractSubnets(allPages)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subnet := range allSubnets {
|
||||||
|
_, tenantIPNet, err := net.ParseCIDR(subnet.CIDR)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cidr := range cidrs {
|
||||||
|
_, candidateIPNet, err := net.ParseCIDR(cidr)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if containsNet(candidateIPNet, tenantIPNet) {
|
||||||
|
return subnet.NetworkID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("failed to discover a provisioning network")
|
||||||
|
}
|
||||||
|
|
||||||
|
// containsNet returns true whenever IPNet `a` contains IPNet `b`
|
||||||
|
func containsNet(a *net.IPNet, b *net.IPNet) bool {
|
||||||
|
aMask, _ := a.Mask.Size()
|
||||||
|
bMask, _ := b.Mask.Size()
|
||||||
|
return a.Contains(b.IP) && aMask <= bMask
|
||||||
|
}
|
345
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/run_config.go
generated
vendored
Normal file
345
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/run_config.go
generated
vendored
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
//go:generate packer-sdc struct-markdown
|
||||||
|
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunConfig contains configuration for running an instance from a source image
|
||||||
|
// and details on how to access that launched image.
|
||||||
|
type RunConfig struct {
|
||||||
|
Comm communicator.Config `mapstructure:",squash"`
|
||||||
|
// The type of interface to connect via SSH. Values useful for Rackspace
|
||||||
|
// are "public" or "private", and the default behavior is to connect via
|
||||||
|
// whichever is returned first from the OpenStack API.
|
||||||
|
SSHInterface string `mapstructure:"ssh_interface" required:"false"`
|
||||||
|
// The IP version to use for SSH connections, valid values are `4` and `6`.
|
||||||
|
// Useful on dual stacked instances where the default behavior is to
|
||||||
|
// connect via whichever IP address is returned first from the OpenStack
|
||||||
|
// API.
|
||||||
|
SSHIPVersion string `mapstructure:"ssh_ip_version" required:"false"`
|
||||||
|
// The ID or full URL to the base image to use. This is the image that will
|
||||||
|
// be used to launch a new server and provision it. Unless you specify
|
||||||
|
// completely custom SSH settings, the source image must have cloud-init
|
||||||
|
// installed so that the keypair gets assigned properly.
|
||||||
|
SourceImage string `mapstructure:"source_image" required:"true"`
|
||||||
|
// The name of the base image to use. This is an alternative way of
|
||||||
|
// providing source_image and only either of them can be specified.
|
||||||
|
SourceImageName string `mapstructure:"source_image_name" required:"true"`
|
||||||
|
// The URL of an external base image to use. This is an alternative way of
|
||||||
|
// providing source_image and only either of them can be specified.
|
||||||
|
ExternalSourceImageURL string `mapstructure:"external_source_image_url" required:"true"`
|
||||||
|
// The format of the external source image to use, e.g. qcow2, raw.
|
||||||
|
ExternalSourceImageFormat string `mapstructure:"external_source_image_format" required:"false"`
|
||||||
|
// Properties to set for the external source image
|
||||||
|
ExternalSourceImageProperties map[string]string `mapstructure:"external_source_image_properties" required:"false"`
|
||||||
|
// Filters used to populate filter options. Example:
|
||||||
|
//
|
||||||
|
// ```json
|
||||||
|
//{
|
||||||
|
// "source_image_filter": {
|
||||||
|
// "filters": {
|
||||||
|
// "name": "ubuntu-16.04",
|
||||||
|
// "visibility": "protected",
|
||||||
|
// "owner": "d1a588cf4b0743344508dc145649372d1",
|
||||||
|
// "tags": ["prod", "ready"],
|
||||||
|
// "properties": {
|
||||||
|
// "os_distro": "ubuntu"
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "most_recent": true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// This selects the most recent production Ubuntu 16.04 shared to you by
|
||||||
|
// the given owner. NOTE: This will fail unless *exactly* one image is
|
||||||
|
// returned, or `most_recent` is set to true. In the example of multiple
|
||||||
|
// returned images, `most_recent` will cause this to succeed by selecting
|
||||||
|
// the newest image of the returned images.
|
||||||
|
//
|
||||||
|
// - `filters` (map of strings) - filters used to select a
|
||||||
|
// `source_image`.
|
||||||
|
// NOTE: This will fail unless *exactly* one image is returned, or
|
||||||
|
// `most_recent` is set to true. Of the filters described in
|
||||||
|
// [ImageService](https://developer.openstack.org/api-ref/image/v2/), the
|
||||||
|
// 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`)
|
||||||
|
//
|
||||||
|
// - `most_recent` (boolean) - Selects the newest created image when
|
||||||
|
// true.
|
||||||
|
// This is most useful for selecting a daily distro build.
|
||||||
|
//
|
||||||
|
// You may set use this in place of `source_image` If `source_image_filter`
|
||||||
|
// is provided alongside `source_image`, the `source_image` will override
|
||||||
|
// the filter. The filter will not be used in this case.
|
||||||
|
SourceImageFilters ImageFilter `mapstructure:"source_image_filter" required:"true"`
|
||||||
|
// The ID, name, or full URL for the desired flavor for the server to be
|
||||||
|
// created.
|
||||||
|
Flavor string `mapstructure:"flavor" required:"true"`
|
||||||
|
// The availability zone to launch the server in. If this isn't specified,
|
||||||
|
// the default enforced by your OpenStack cluster will be used. This may be
|
||||||
|
// required for some OpenStack clusters.
|
||||||
|
AvailabilityZone string `mapstructure:"availability_zone" required:"false"`
|
||||||
|
// For rackspace, whether or not to wait for Rackconnect to assign the
|
||||||
|
// machine an IP address before connecting via SSH. Defaults to false.
|
||||||
|
RackconnectWait bool `mapstructure:"rackconnect_wait" required:"false"`
|
||||||
|
// The ID or name of an external network that can be used for creation of a
|
||||||
|
// new floating IP.
|
||||||
|
FloatingIPNetwork string `mapstructure:"floating_ip_network" required:"false"`
|
||||||
|
// The ID of the network to which the instance is attached and which should
|
||||||
|
// be used to associate with the floating IP. This provides control over
|
||||||
|
// the floating ip association on multi-homed instances. The association
|
||||||
|
// otherwise depends on a first-returned-interface policy which could fail
|
||||||
|
// if the network to which it is connected is unreachable from the floating
|
||||||
|
// IP network.
|
||||||
|
InstanceFloatingIPNet string `mapstructure:"instance_floating_ip_net" required:"false"`
|
||||||
|
// A specific floating IP to assign to this instance.
|
||||||
|
FloatingIP string `mapstructure:"floating_ip" required:"false"`
|
||||||
|
// Whether or not to attempt to reuse existing unassigned floating ips in
|
||||||
|
// the project before allocating a new one. Note that it is not possible to
|
||||||
|
// safely do this concurrently, so if you are running multiple openstack
|
||||||
|
// builds concurrently, or if other processes are assigning and using
|
||||||
|
// floating IPs in the same openstack project while packer is running, you
|
||||||
|
// should not set this to true. Defaults to false.
|
||||||
|
ReuseIPs bool `mapstructure:"reuse_ips" required:"false"`
|
||||||
|
// A list of security groups by name to add to this instance.
|
||||||
|
SecurityGroups []string `mapstructure:"security_groups" required:"false"`
|
||||||
|
// A list of networks by UUID to attach to this instance.
|
||||||
|
Networks []string `mapstructure:"networks" required:"false"`
|
||||||
|
// A list of ports by UUID to attach to this instance.
|
||||||
|
Ports []string `mapstructure:"ports" required:"false"`
|
||||||
|
// A list of network CIDRs to discover the network to attach to this instance.
|
||||||
|
// The first network whose subnet is contained within any of the given CIDRs
|
||||||
|
// is used. Ignored if either of the above two options are provided.
|
||||||
|
NetworkDiscoveryCIDRs []string `mapstructure:"network_discovery_cidrs" required:"false"`
|
||||||
|
// User data to apply when launching the instance. Note that you need to be
|
||||||
|
// careful about escaping characters due to the templates being JSON. It is
|
||||||
|
// often more convenient to use user_data_file, instead. Packer will not
|
||||||
|
// automatically wait for a user script to finish before shutting down the
|
||||||
|
// instance this must be handled in a provisioner.
|
||||||
|
UserData string `mapstructure:"user_data" required:"false"`
|
||||||
|
// Path to a file that will be used for the user data when launching the
|
||||||
|
// instance.
|
||||||
|
UserDataFile string `mapstructure:"user_data_file" required:"false"`
|
||||||
|
// Name that is applied to the server instance created by Packer. If this
|
||||||
|
// isn't specified, the default is same as image_name.
|
||||||
|
InstanceName string `mapstructure:"instance_name" required:"false"`
|
||||||
|
// Metadata that is applied to the server instance created by Packer. Also
|
||||||
|
// called server properties in some documentation. The strings have a max
|
||||||
|
// size of 255 bytes each.
|
||||||
|
InstanceMetadata map[string]string `mapstructure:"instance_metadata" required:"false"`
|
||||||
|
// Whether to force the OpenStack instance to be forcefully deleted. This
|
||||||
|
// is useful for environments that have reclaim / soft deletion enabled. By
|
||||||
|
// default this is false.
|
||||||
|
ForceDelete bool `mapstructure:"force_delete" required:"false"`
|
||||||
|
// Whether or not nova should use ConfigDrive for cloud-init metadata.
|
||||||
|
ConfigDrive bool `mapstructure:"config_drive" required:"false"`
|
||||||
|
// Deprecated use floating_ip_network instead.
|
||||||
|
FloatingIPPool string `mapstructure:"floating_ip_pool" required:"false"`
|
||||||
|
// Use Block Storage service volume for the instance root volume instead of
|
||||||
|
// Compute service local volume (default).
|
||||||
|
UseBlockStorageVolume bool `mapstructure:"use_blockstorage_volume" required:"false"`
|
||||||
|
// Name of the Block Storage service volume. If this isn't specified,
|
||||||
|
// random string will be used.
|
||||||
|
VolumeName string `mapstructure:"volume_name" required:"false"`
|
||||||
|
// Type of the Block Storage service volume. If this isn't specified, the
|
||||||
|
// default enforced by your OpenStack cluster will be used.
|
||||||
|
VolumeType string `mapstructure:"volume_type" required:"false"`
|
||||||
|
// Size of the Block Storage service volume in GB. If this isn't specified,
|
||||||
|
// it is set to source image min disk value (if set) or calculated from the
|
||||||
|
// source image bytes size. Note that in some cases this needs to be
|
||||||
|
// specified, if use_blockstorage_volume is true.
|
||||||
|
VolumeSize int `mapstructure:"volume_size" required:"false"`
|
||||||
|
// Availability zone of the Block Storage service volume. If omitted,
|
||||||
|
// Compute instance availability zone will be used. If both of Compute
|
||||||
|
// instance and Block Storage volume availability zones aren't specified,
|
||||||
|
// the default enforced by your OpenStack cluster will be used.
|
||||||
|
VolumeAvailabilityZone string `mapstructure:"volume_availability_zone" required:"false"`
|
||||||
|
|
||||||
|
// Not really used, but here for BC
|
||||||
|
OpenstackProvider string `mapstructure:"openstack_provider"`
|
||||||
|
// *Deprecated* use `floating_ip` or `floating_ip_pool` instead.
|
||||||
|
UseFloatingIp bool `mapstructure:"use_floating_ip" required:"false"`
|
||||||
|
|
||||||
|
sourceImageOpts images.ListOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageFilter struct {
|
||||||
|
// filters used to select a source_image. NOTE: This will fail unless
|
||||||
|
// exactly one image is returned, or most_recent is set to true. Of the
|
||||||
|
// filters described in ImageService, the following are valid:
|
||||||
|
Filters ImageFilterOptions `mapstructure:"filters" required:"false"`
|
||||||
|
// Selects the newest created image when true. This is most useful for
|
||||||
|
// selecting a daily distro build.
|
||||||
|
MostRecent bool `mapstructure:"most_recent" required:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageFilterOptions struct {
|
||||||
|
Name string `mapstructure:"name"`
|
||||||
|
Owner string `mapstructure:"owner"`
|
||||||
|
Tags []string `mapstructure:"tags"`
|
||||||
|
Visibility string `mapstructure:"visibility"`
|
||||||
|
Properties map[string]string `mapstructure:"properties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ImageFilterOptions) Empty() bool {
|
||||||
|
return f.Name == "" && f.Owner == "" && len(f.Tags) == 0 && f.Visibility == "" && len(f.Properties) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ImageFilterOptions) Build() (*images.ListOpts, error) {
|
||||||
|
opts := images.ListOpts{}
|
||||||
|
// Set defaults for status, member_status, and sort
|
||||||
|
opts.Status = images.ImageStatusActive
|
||||||
|
opts.MemberStatus = images.ImageMemberStatusAccepted
|
||||||
|
opts.Sort = "created_at:desc"
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if f.Name != "" {
|
||||||
|
opts.Name = f.Name
|
||||||
|
}
|
||||||
|
if f.Owner != "" {
|
||||||
|
opts.Owner = f.Owner
|
||||||
|
}
|
||||||
|
if len(f.Tags) > 0 {
|
||||||
|
opts.Tags = f.Tags
|
||||||
|
}
|
||||||
|
if f.Visibility != "" {
|
||||||
|
v, err := getImageVisibility(f.Visibility)
|
||||||
|
if err == nil {
|
||||||
|
opts.Visibility = *v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &opts, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
|
// If we are not given an explicit ssh_keypair_name or
|
||||||
|
// ssh_private_key_file, then create a temporary one, but only if the
|
||||||
|
// temporary_key_pair_name has not been provided and we are not using
|
||||||
|
// ssh_password.
|
||||||
|
if c.Comm.SSHKeyPairName == "" && c.Comm.SSHTemporaryKeyPairName == "" &&
|
||||||
|
c.Comm.SSHPrivateKeyFile == "" && c.Comm.SSHPassword == "" {
|
||||||
|
|
||||||
|
c.Comm.SSHTemporaryKeyPairName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.FloatingIPPool != "" && c.FloatingIPNetwork == "" {
|
||||||
|
c.FloatingIPNetwork = c.FloatingIPPool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation
|
||||||
|
errs := c.Comm.Prepare(ctx)
|
||||||
|
|
||||||
|
if c.Comm.SSHKeyPairName != "" {
|
||||||
|
if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKeyFile == "" {
|
||||||
|
errs = append(errs, errors.New("A ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
|
||||||
|
} else if c.Comm.SSHPrivateKeyFile == "" && !c.Comm.SSHAgentAuth {
|
||||||
|
errs = append(errs, errors.New("A ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.SourceImage == "" && c.SourceImageName == "" && c.ExternalSourceImageURL == "" && c.SourceImageFilters.Filters.Empty() {
|
||||||
|
errs = append(errs, errors.New("Either a source_image, a source_image_name, an external_source_image_url or source_image_filter must be specified"))
|
||||||
|
} else {
|
||||||
|
// Make sure we've only set one image source option
|
||||||
|
thereCanBeOnlyOne := []bool{len(c.SourceImageName) > 0, len(c.SourceImage) > 0, len(c.ExternalSourceImageURL) > 0, !c.SourceImageFilters.Filters.Empty()}
|
||||||
|
numSet := 0
|
||||||
|
for _, val := range thereCanBeOnlyOne {
|
||||||
|
if val {
|
||||||
|
numSet += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if numSet > 1 {
|
||||||
|
errs = append(errs, errors.New("Only one of the options source_image, source_image_name, external_source_image_url, or source_image_filter can be specified, not multiple."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if external_source_image_format is not set use qcow2 as default
|
||||||
|
if c.ExternalSourceImageFormat == "" {
|
||||||
|
c.ExternalSourceImageFormat = "qcow2"
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Flavor == "" {
|
||||||
|
errs = append(errs, errors.New("A flavor must be specified"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.SSHIPVersion != "" && c.SSHIPVersion != "4" && c.SSHIPVersion != "6" {
|
||||||
|
errs = append(errs, errors.New("SSH IP version must be either 4 or 6"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range c.InstanceMetadata {
|
||||||
|
if len(key) > 255 {
|
||||||
|
errs = append(errs, fmt.Errorf("Instance metadata key too long (max 255 bytes): %s", key))
|
||||||
|
}
|
||||||
|
if len(value) > 255 {
|
||||||
|
errs = append(errs, fmt.Errorf("Instance metadata value too long (max 255 bytes): %s", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.UseBlockStorageVolume {
|
||||||
|
// Use Compute instance availability zone for the Block Storage volume
|
||||||
|
// if it's not provided.
|
||||||
|
if c.VolumeAvailabilityZone == "" {
|
||||||
|
c.VolumeAvailabilityZone = c.AvailabilityZone
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use random name for the Block Storage volume if it's not provided.
|
||||||
|
if c.VolumeName == "" {
|
||||||
|
c.VolumeName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if neither ID, image name or external image URL is provided outside the filter,
|
||||||
|
// build the filter
|
||||||
|
if len(c.SourceImage) == 0 && len(c.SourceImageName) == 0 && len(c.ExternalSourceImageURL) == 0 {
|
||||||
|
|
||||||
|
listOpts, filterErr := c.SourceImageFilters.Filters.Build()
|
||||||
|
|
||||||
|
if filterErr != nil {
|
||||||
|
errs = append(errs, filterErr)
|
||||||
|
}
|
||||||
|
c.sourceImageOpts = *listOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
// if c.ExternalSourceImageURL is set use a generated source image name
|
||||||
|
if c.ExternalSourceImageURL != "" {
|
||||||
|
c.SourceImageName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the specific ImageVisibility using the exported const from images
|
||||||
|
func getImageVisibility(visibility string) (*images.ImageVisibility, error) {
|
||||||
|
visibilities := [...]images.ImageVisibility{
|
||||||
|
images.ImageVisibilityPublic,
|
||||||
|
images.ImageVisibilityPrivate,
|
||||||
|
images.ImageVisibilityCommunity,
|
||||||
|
images.ImageVisibilityShared,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range visibilities {
|
||||||
|
if string(v) == visibility {
|
||||||
|
return &v, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Not a valid visibility: %s", visibility)
|
||||||
|
}
|
93
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/server.go
generated
vendored
Normal file
93
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/server.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StateRefreshFunc is a function type used for StateChangeConf that is
|
||||||
|
// responsible for refreshing the item being watched for a state change.
|
||||||
|
//
|
||||||
|
// It returns three results. `result` is any object that will be returned
|
||||||
|
// as the final object after waiting for state change. This allows you to
|
||||||
|
// return the final updated object, for example an openstack instance after
|
||||||
|
// refreshing it.
|
||||||
|
//
|
||||||
|
// `state` is the latest state of that object. And `err` is any error that
|
||||||
|
// may have happened while refreshing the state.
|
||||||
|
type StateRefreshFunc func() (result interface{}, state string, progress int, err error)
|
||||||
|
|
||||||
|
// StateChangeConf is the configuration struct used for `WaitForState`.
|
||||||
|
type StateChangeConf struct {
|
||||||
|
Pending []string
|
||||||
|
Refresh StateRefreshFunc
|
||||||
|
StepState multistep.StateBag
|
||||||
|
Target []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerStateRefreshFunc returns a StateRefreshFunc that is used to watch
|
||||||
|
// an openstack server.
|
||||||
|
func ServerStateRefreshFunc(
|
||||||
|
client *gophercloud.ServiceClient, s *servers.Server) StateRefreshFunc {
|
||||||
|
return func() (interface{}, string, int, error) {
|
||||||
|
serverNew, err := servers.Get(client, s.ID).Extract()
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(gophercloud.ErrDefault404); ok {
|
||||||
|
log.Printf("[INFO] 404 on ServerStateRefresh, returning DELETED")
|
||||||
|
return nil, "DELETED", 0, nil
|
||||||
|
}
|
||||||
|
log.Printf("[ERROR] Error on ServerStateRefresh: %s", err)
|
||||||
|
return nil, "", 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverNew, serverNew.Status, serverNew.Progress, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForState watches an object and waits for it to achieve a certain
|
||||||
|
// state.
|
||||||
|
func WaitForState(conf *StateChangeConf) (i interface{}, err error) {
|
||||||
|
log.Printf("Waiting for state to become: %s", conf.Target)
|
||||||
|
|
||||||
|
for {
|
||||||
|
var currentProgress int
|
||||||
|
var currentState string
|
||||||
|
i, currentState, currentProgress, err = conf.Refresh()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range conf.Target {
|
||||||
|
if currentState == t {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.StepState != nil {
|
||||||
|
if _, ok := conf.StepState.GetOk(multistep.StateCancelled); ok {
|
||||||
|
return nil, errors.New("interrupted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found := false
|
||||||
|
for _, allowed := range conf.Pending {
|
||||||
|
if currentState == allowed {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("unexpected state '%s', wanted target '%s'", currentState, conf.Target)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Waiting for state to become: %s currently %s (%d%%)", conf.Target, currentState, currentProgress)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
116
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/ssh.go
generated
vendored
Normal file
116
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/ssh.go
generated
vendored
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommHost looks up the host for the communicator.
|
||||||
|
func CommHost(
|
||||||
|
host string,
|
||||||
|
client *gophercloud.ServiceClient,
|
||||||
|
sshinterface string,
|
||||||
|
sshipversion string) func(multistep.StateBag) (string, error) {
|
||||||
|
return func(state multistep.StateBag) (string, error) {
|
||||||
|
if host != "" {
|
||||||
|
log.Printf("Using host value: %s", host)
|
||||||
|
return host, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s := state.Get("server").(*servers.Server)
|
||||||
|
|
||||||
|
// If we have a specific interface, try that
|
||||||
|
if sshinterface != "" {
|
||||||
|
if addr := sshAddrFromPool(s, sshinterface, sshipversion); addr != "" {
|
||||||
|
log.Printf("[DEBUG] Using IP address %s from specified interface %s to connect", addr, sshinterface)
|
||||||
|
return addr, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a floating IP, use that
|
||||||
|
ip := state.Get("access_ip").(*floatingips.FloatingIP)
|
||||||
|
if ip != nil && ip.FloatingIP != "" {
|
||||||
|
log.Printf("[DEBUG] Using floating IP %s to connect", ip.FloatingIP)
|
||||||
|
return ip.FloatingIP, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.AccessIPv4 != "" {
|
||||||
|
log.Printf("[DEBUG] Using AccessIPv4 %s to connect", s.AccessIPv4)
|
||||||
|
return s.AccessIPv4, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get it from the requested interface
|
||||||
|
if addr := sshAddrFromPool(s, sshinterface, sshipversion); addr != "" {
|
||||||
|
log.Printf("[DEBUG] Using IP address %s to connect", addr)
|
||||||
|
return addr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := servers.Get(client, s.ID).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Put("server", s)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
return "", errors.New("couldn't determine IP address for server")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sshAddrFromPool(s *servers.Server, desired string, sshIPVersion string) string {
|
||||||
|
// Get all the addresses associated with this server. This
|
||||||
|
// was taken directly from Terraform.
|
||||||
|
for pool, networkAddresses := range s.Addresses {
|
||||||
|
// If we have an SSH interface specified, skip it if no match
|
||||||
|
if desired != "" && pool != desired {
|
||||||
|
log.Printf(
|
||||||
|
"[INFO] Skipping pool %s, doesn't match requested %s",
|
||||||
|
pool, desired)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
elements, ok := networkAddresses.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
log.Printf(
|
||||||
|
"[ERROR] Unknown return type for address field: %#v",
|
||||||
|
networkAddresses)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, element := range elements {
|
||||||
|
var addr string
|
||||||
|
address := element.(map[string]interface{})
|
||||||
|
if address["OS-EXT-IPS:type"] == "floating" {
|
||||||
|
addr = address["addr"].(string)
|
||||||
|
} else if sshIPVersion == "4" {
|
||||||
|
if address["version"].(float64) == 4 {
|
||||||
|
addr = address["addr"].(string)
|
||||||
|
}
|
||||||
|
} else if sshIPVersion == "6" {
|
||||||
|
if address["version"].(float64) == 6 {
|
||||||
|
addr = fmt.Sprintf("[%s]", address["addr"].(string))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if address["version"].(float64) == 6 {
|
||||||
|
addr = fmt.Sprintf("[%s]", address["addr"].(string))
|
||||||
|
} else {
|
||||||
|
addr = address["addr"].(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr != "" {
|
||||||
|
log.Printf("[DEBUG] Detected address: %s", addr)
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
63
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_add_image_members.go
generated
vendored
Normal file
63
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_add_image_members.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/members"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stepAddImageMembers struct{}
|
||||||
|
|
||||||
|
func (s *stepAddImageMembers) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
|
||||||
|
if config.SkipCreateImage {
|
||||||
|
ui.Say("Skipping image add members...")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
imageId := state.Get("image").(string)
|
||||||
|
|
||||||
|
if len(config.ImageMembers) == 0 {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
imageClient, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing image service client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, member := range config.ImageMembers {
|
||||||
|
ui.Say(fmt.Sprintf("Adding member '%s' to image %s", member, imageId))
|
||||||
|
r := members.Create(imageClient, imageId, member)
|
||||||
|
if _, err = r.Extract(); err != nil {
|
||||||
|
err = fmt.Errorf("Error adding member to image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.ImageAutoAcceptMembers {
|
||||||
|
for _, member := range config.ImageMembers {
|
||||||
|
ui.Say(fmt.Sprintf("Accepting image %s for member '%s'", imageId, member))
|
||||||
|
r := members.Update(imageClient, imageId, member, members.UpdateOpts{Status: "accepted"})
|
||||||
|
if _, err = r.Extract(); err != nil {
|
||||||
|
err = fmt.Errorf("Error accepting image for member: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepAddImageMembers) Cleanup(multistep.StateBag) {
|
||||||
|
// No cleanup...
|
||||||
|
}
|
178
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_allocate_ip.go
generated
vendored
Normal file
178
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_allocate_ip.go
generated
vendored
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepAllocateIp struct {
|
||||||
|
FloatingIPNetwork string
|
||||||
|
FloatingIP string
|
||||||
|
ReuseIPs bool
|
||||||
|
InstanceFloatingIPNet string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepAllocateIp) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
server := state.Get("server").(*servers.Server)
|
||||||
|
|
||||||
|
var instanceIP floatingips.FloatingIP
|
||||||
|
|
||||||
|
// This is here in case we error out before putting instanceIp into the
|
||||||
|
// statebag below, because it is requested by Cleanup()
|
||||||
|
state.Put("access_ip", &instanceIP)
|
||||||
|
|
||||||
|
if s.FloatingIP == "" && !s.ReuseIPs && s.FloatingIPNetwork == "" {
|
||||||
|
ui.Message("Floating IP not required")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
computeClient, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need the v2 network client
|
||||||
|
networkClient, err := config.networkV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing network client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to Use the OpenStack floating IP by checking provided parameters in
|
||||||
|
// the following order:
|
||||||
|
// - try to use "FloatingIP" ID directly if it's provided
|
||||||
|
// - try to find free floating IP in the project if "ReuseIPs" is set
|
||||||
|
// - create a new floating IP if "FloatingIPNetwork" is provided (it can be
|
||||||
|
// ID or name of the network).
|
||||||
|
if s.FloatingIP != "" {
|
||||||
|
// Try to use FloatingIP if it was provided by the user.
|
||||||
|
freeFloatingIP, err := CheckFloatingIP(networkClient, s.FloatingIP)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error using provided floating IP '%s': %s", s.FloatingIP, err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceIP = *freeFloatingIP
|
||||||
|
ui.Message(fmt.Sprintf("Selected floating IP: '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
|
||||||
|
state.Put("floatingip_istemp", false)
|
||||||
|
} else if s.ReuseIPs {
|
||||||
|
// If ReuseIPs is set to true and we have a free floating IP, use it rather
|
||||||
|
// than creating one.
|
||||||
|
ui.Say(fmt.Sprint("Searching for unassociated floating IP"))
|
||||||
|
freeFloatingIP, err := FindFreeFloatingIP(networkClient)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error searching for floating IP: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceIP = *freeFloatingIP
|
||||||
|
ui.Message(fmt.Sprintf("Selected floating IP: '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
|
||||||
|
state.Put("floatingip_istemp", false)
|
||||||
|
} else if s.FloatingIPNetwork != "" {
|
||||||
|
// Lastly, if FloatingIPNetwork was provided by the user, we need to use it
|
||||||
|
// to allocate a new floating IP and associate it to the instance.
|
||||||
|
floatingNetwork, err := CheckFloatingIPNetwork(networkClient, s.FloatingIPNetwork)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error using the provided floating_ip_network: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Creating floating IP using network %s ...", floatingNetwork))
|
||||||
|
newIP, err := floatingips.Create(networkClient, floatingips.CreateOpts{
|
||||||
|
FloatingNetworkID: floatingNetwork,
|
||||||
|
}).Extract()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error creating floating IP from floating network '%s': %s", floatingNetwork, err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceIP = *newIP
|
||||||
|
ui.Message(fmt.Sprintf("Created floating IP: '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
|
||||||
|
state.Put("floatingip_istemp", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assoctate a floating IP if it was obtained in the previous steps.
|
||||||
|
if instanceIP.ID != "" {
|
||||||
|
ui.Say(fmt.Sprintf("Associating floating IP '%s' (%s) with instance port...",
|
||||||
|
instanceIP.ID, instanceIP.FloatingIP))
|
||||||
|
|
||||||
|
portID, err := GetInstancePortID(computeClient, server.ID, s.InstanceFloatingIPNet)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error getting interfaces of the instance '%s': %s", server.ID, err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = floatingips.Update(networkClient, instanceIP.ID, floatingips.UpdateOpts{
|
||||||
|
PortID: &portID,
|
||||||
|
}).Extract()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"Error associating floating IP '%s' (%s) with instance port '%s': %s",
|
||||||
|
instanceIP.ID, instanceIP.FloatingIP, portID, err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf(
|
||||||
|
"Added floating IP '%s' (%s) to instance!", instanceIP.ID, instanceIP.FloatingIP))
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Put("access_ip", &instanceIP)
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepAllocateIp) Cleanup(state multistep.StateBag) {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
instanceIP := state.Get("access_ip").(*floatingips.FloatingIP)
|
||||||
|
|
||||||
|
// Don't clean up if unless required
|
||||||
|
if instanceIP.ID == "" && instanceIP.FloatingIP == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't delete pool addresses we didn't allocate
|
||||||
|
if state.Get("floatingip_istemp") == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need the v2 network client
|
||||||
|
client, err := config.networkV2Client()
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error deleting temporary floating IP '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if instanceIP.ID != "" {
|
||||||
|
if err := floatingips.Delete(client, instanceIP.ID).ExtractErr(); err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error deleting temporary floating IP '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Deleted temporary floating IP '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
|
||||||
|
}
|
||||||
|
}
|
152
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_create_image.go
generated
vendored
Normal file
152
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_create_image.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stepCreateImage struct {
|
||||||
|
UseBlockStorageVolume bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
server := state.Get("server").(*servers.Server)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
if config.SkipCreateImage {
|
||||||
|
ui.Say("Skipping image creation...")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
computeClient, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need the v2 image client
|
||||||
|
imageClient, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing image service client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the image.
|
||||||
|
// Image source depends on the type of the Compute instance. It can be
|
||||||
|
// Block Storage service volume or regular Compute service local volume.
|
||||||
|
ui.Say(fmt.Sprintf("Creating the image: %s", config.ImageName))
|
||||||
|
var imageId string
|
||||||
|
var blockStorageClient *gophercloud.ServiceClient
|
||||||
|
if s.UseBlockStorageVolume {
|
||||||
|
// We need the v3 block storage client.
|
||||||
|
blockStorageClient, err = config.blockStorageV3Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing block storage client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
volume := state.Get("volume_id").(string)
|
||||||
|
|
||||||
|
// set ImageMetadata before uploading to glance so the new image captured the desired values
|
||||||
|
if len(config.ImageMetadata) > 0 {
|
||||||
|
err = volumeactions.SetImageMetadata(blockStorageClient, volume, volumeactions.ImageMetadataOpts{
|
||||||
|
Metadata: config.ImageMetadata,
|
||||||
|
}).ExtractErr()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error setting image metadata: %s", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
image, err := volumeactions.UploadImage(blockStorageClient, volume, volumeactions.UploadImageOpts{
|
||||||
|
DiskFormat: config.ImageDiskFormat,
|
||||||
|
ImageName: config.ImageName,
|
||||||
|
}).Extract()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error creating image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
imageId = image.ImageID
|
||||||
|
} else {
|
||||||
|
imageId, err = servers.CreateImage(computeClient, server.ID, servers.CreateImageOpts{
|
||||||
|
Name: config.ImageName,
|
||||||
|
Metadata: config.ImageMetadata,
|
||||||
|
}).ExtractImageID()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error creating image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the Image ID in the state
|
||||||
|
ui.Message(fmt.Sprintf("Image: %s", imageId))
|
||||||
|
state.Put("image", imageId)
|
||||||
|
|
||||||
|
// Wait for the image to become ready
|
||||||
|
ui.Say(fmt.Sprintf("Waiting for image %s (image id: %s) to become ready...", config.ImageName, imageId))
|
||||||
|
if err := WaitForImage(ctx, imageClient, imageId); err != nil {
|
||||||
|
err := fmt.Errorf("Error waiting for image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepCreateImage) Cleanup(multistep.StateBag) {
|
||||||
|
// No cleanup...
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForImage waits for the given Image ID to become ready.
|
||||||
|
func WaitForImage(ctx context.Context, client *gophercloud.ServiceClient, imageId string) error {
|
||||||
|
maxNumErrors := 10
|
||||||
|
numErrors := 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
image, err := images.Get(client, imageId).Extract()
|
||||||
|
if err != nil {
|
||||||
|
errCode, ok := err.(*gophercloud.ErrUnexpectedResponseCode)
|
||||||
|
if ok && (errCode.Actual == 500 || errCode.Actual == 404) {
|
||||||
|
numErrors++
|
||||||
|
if numErrors >= maxNumErrors {
|
||||||
|
log.Printf("[ERROR] Maximum number of errors (%d) reached; failing with: %s", numErrors, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[ERROR] %d error received, will ignore and retry: %s", errCode.Actual, err)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if image.Status == "active" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Waiting for image creation status: %s", image.Status)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
134
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_create_volume.go
generated
vendored
Normal file
134
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_create_volume.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepCreateVolume struct {
|
||||||
|
UseBlockStorageVolume bool
|
||||||
|
VolumeName string
|
||||||
|
VolumeType string
|
||||||
|
VolumeAvailabilityZone string
|
||||||
|
volumeID string
|
||||||
|
doCleanup bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepCreateVolume) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
// Proceed only if block storage volume is required.
|
||||||
|
if !s.UseBlockStorageVolume {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
sourceImage := state.Get("source_image").(string)
|
||||||
|
|
||||||
|
// We will need Block Storage and Image services clients.
|
||||||
|
blockStorageClient, err := config.blockStorageV3Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing block storage client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
volumeSize := config.VolumeSize
|
||||||
|
|
||||||
|
// Get needed volume size from the source image.
|
||||||
|
if volumeSize == 0 {
|
||||||
|
imageClient, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing image client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
volumeSize, err = GetVolumeSize(imageClient, sourceImage)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error creating volume: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Creating volume...")
|
||||||
|
volumeOpts := volumes.CreateOpts{
|
||||||
|
Size: volumeSize,
|
||||||
|
VolumeType: s.VolumeType,
|
||||||
|
AvailabilityZone: s.VolumeAvailabilityZone,
|
||||||
|
Name: s.VolumeName,
|
||||||
|
ImageID: sourceImage,
|
||||||
|
Metadata: config.ImageMetadata,
|
||||||
|
}
|
||||||
|
volume, err := volumes.Create(blockStorageClient, volumeOpts).Extract()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error creating volume: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for volume to become available.
|
||||||
|
ui.Say(fmt.Sprintf("Waiting for volume %s (volume id: %s) to become available...", config.VolumeName, volume.ID))
|
||||||
|
if err := WaitForVolume(blockStorageClient, volume.ID); err != nil {
|
||||||
|
err := fmt.Errorf("Error waiting for volume: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume was created, so remember to clean it up.
|
||||||
|
s.doCleanup = true
|
||||||
|
|
||||||
|
// Set the Volume ID in the state.
|
||||||
|
ui.Message(fmt.Sprintf("Volume ID: %s", volume.ID))
|
||||||
|
state.Put("volume_id", volume.ID)
|
||||||
|
s.volumeID = volume.ID
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepCreateVolume) Cleanup(state multistep.StateBag) {
|
||||||
|
if !s.doCleanup {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
blockStorageClient, err := config.blockStorageV3Client()
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error cleaning up volume. Please delete the volume manually: %s", s.volumeID))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for volume to become available.
|
||||||
|
status, err := GetVolumeStatus(blockStorageClient, s.volumeID)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error getting the volume information. Please delete the volume manually: %s", s.volumeID))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != "available" {
|
||||||
|
ui.Say(fmt.Sprintf(
|
||||||
|
"Waiting for volume %s (volume id: %s) to become available...", s.VolumeName, s.volumeID))
|
||||||
|
if err := WaitForVolume(blockStorageClient, s.volumeID); err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error getting the volume information. Please delete the volume manually: %s", s.volumeID))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.Say(fmt.Sprintf("Deleting volume: %s ...", s.volumeID))
|
||||||
|
err = volumes.Delete(blockStorageClient, s.volumeID, volumes.DeleteOpts{}).ExtractErr()
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error cleaning up volume. Please delete the volume manually: %s", s.volumeID))
|
||||||
|
}
|
||||||
|
}
|
54
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_detach_volume.go
generated
vendored
Normal file
54
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_detach_volume.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepDetachVolume struct {
|
||||||
|
UseBlockStorageVolume bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepDetachVolume) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
// Proceed only if block storage volume is used.
|
||||||
|
if !s.UseBlockStorageVolume {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
blockStorageClient, err := config.blockStorageV3Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing block storage client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
volume := state.Get("volume_id").(string)
|
||||||
|
ui.Say(fmt.Sprintf("Detaching volume %s (volume id: %s)", config.VolumeName, volume))
|
||||||
|
if err := volumeactions.Detach(blockStorageClient, volume, volumeactions.DetachOpts{}).ExtractErr(); err != nil {
|
||||||
|
err = fmt.Errorf("Error detaching block storage volume: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for volume to become available.
|
||||||
|
ui.Say(fmt.Sprintf("Waiting for volume %s (volume id: %s) to become available...", config.VolumeName, volume))
|
||||||
|
if err := WaitForVolume(blockStorageClient, volume); err != nil {
|
||||||
|
err := fmt.Errorf("Error waiting for volume: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepDetachVolume) Cleanup(multistep.StateBag) {
|
||||||
|
// No cleanup.
|
||||||
|
}
|
55
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_discover_network.go
generated
vendored
Normal file
55
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_discover_network.go
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepDiscoverNetwork struct {
|
||||||
|
Networks []string
|
||||||
|
NetworkDiscoveryCIDRs []string
|
||||||
|
Ports []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepDiscoverNetwork) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
networkClient, err := config.networkV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing network client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
networks := []servers.Network{}
|
||||||
|
for _, port := range s.Ports {
|
||||||
|
networks = append(networks, servers.Network{Port: port})
|
||||||
|
}
|
||||||
|
for _, uuid := range s.Networks {
|
||||||
|
networks = append(networks, servers.Network{UUID: uuid})
|
||||||
|
}
|
||||||
|
|
||||||
|
cidrs := s.NetworkDiscoveryCIDRs
|
||||||
|
if len(networks) == 0 && len(cidrs) > 0 {
|
||||||
|
ui.Say(fmt.Sprintf("Discovering provisioning network..."))
|
||||||
|
|
||||||
|
networkID, err := DiscoverProvisioningNetwork(networkClient, cidrs)
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Found network ID: %s", networkID))
|
||||||
|
networks = append(networks, servers.Network{UUID: networkID})
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Put("networks", networks)
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepDiscoverNetwork) Cleanup(state multistep.StateBag) {}
|
85
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_get_password.go
generated
vendored
Normal file
85
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_get_password.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rsa"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StepGetPassword reads the password from a booted OpenStack server and sets
|
||||||
|
// it on the WinRM config.
|
||||||
|
type StepGetPassword struct {
|
||||||
|
Debug bool
|
||||||
|
Comm *communicator.Config
|
||||||
|
BuildName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepGetPassword) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
// Skip if we're not using winrm
|
||||||
|
if s.Comm.Type != "winrm" {
|
||||||
|
log.Printf("[INFO] Not using winrm communicator, skipping get password...")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we already have a password, skip it
|
||||||
|
if s.Comm.WinRMPassword != "" {
|
||||||
|
ui.Say("Skipping waiting for password since WinRM password set...")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
computeClient, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Waiting for password since WinRM password is not set...")
|
||||||
|
server := state.Get("server").(*servers.Server)
|
||||||
|
var password string
|
||||||
|
|
||||||
|
privateKey, err := ssh.ParseRawPrivateKey(s.Comm.SSHPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error parsing private key: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; password == "" && err == nil; password, err = servers.GetPassword(computeClient, server.ID).ExtractPassword(privateKey.(*rsa.PrivateKey)) {
|
||||||
|
|
||||||
|
// Check for an interrupt in between attempts.
|
||||||
|
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Retrying to get a administrator password evry 5 seconds.")
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Password retrieved!"))
|
||||||
|
s.Comm.WinRMPassword = password
|
||||||
|
|
||||||
|
// In debug-mode, we output the password
|
||||||
|
if s.Debug {
|
||||||
|
ui.Message(fmt.Sprintf(
|
||||||
|
"Password (since debug is enabled) \"%s\"", s.Comm.WinRMPassword))
|
||||||
|
}
|
||||||
|
|
||||||
|
packersdk.LogSecretFilter.Set(s.Comm.WinRMPassword)
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepGetPassword) Cleanup(multistep.StateBag) {}
|
190
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_key_pair.go
generated
vendored
Normal file
190
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_key_pair.go
generated
vendored
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/communicator"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/tmp"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepKeyPair struct {
|
||||||
|
Debug bool
|
||||||
|
Comm *communicator.Config
|
||||||
|
DebugKeyPath string
|
||||||
|
|
||||||
|
doCleanup bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepKeyPair) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
if s.Comm.SSHPrivateKeyFile != "" {
|
||||||
|
ui.Say("Using existing SSH private key")
|
||||||
|
privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile()
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Comm.SSHPrivateKey = privateKeyBytes
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Comm.SSHAgentAuth && s.Comm.SSHKeyPairName == "" {
|
||||||
|
ui.Say("Using SSH Agent with key pair in Source image")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Comm.SSHAgentAuth && s.Comm.SSHKeyPairName != "" {
|
||||||
|
ui.Say(fmt.Sprintf("Using SSH Agent for existing key pair %s", s.Comm.SSHKeyPairName))
|
||||||
|
s.Comm.SSHKeyPairName = ""
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Comm.SSHTemporaryKeyPairName == "" {
|
||||||
|
ui.Say("Not using temporary keypair")
|
||||||
|
s.Comm.SSHKeyPairName = ""
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
computeClient, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Creating temporary keypair: %s ...", s.Comm.SSHTemporaryKeyPairName))
|
||||||
|
keypair, err := keypairs.Create(computeClient, keypairs.CreateOpts{
|
||||||
|
Name: s.Comm.SSHTemporaryKeyPairName,
|
||||||
|
}).Extract()
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", fmt.Errorf("Error creating temporary keypair: %s", err))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(keypair.PrivateKey) == 0 {
|
||||||
|
state.Put("error", fmt.Errorf("The temporary keypair returned was blank"))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Created temporary keypair: %s", s.Comm.SSHTemporaryKeyPairName))
|
||||||
|
|
||||||
|
keypair.PrivateKey = string(berToDer([]byte(keypair.PrivateKey), ui))
|
||||||
|
|
||||||
|
// If we're in debug mode, output the private key to the working
|
||||||
|
// directory.
|
||||||
|
if s.Debug {
|
||||||
|
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
|
||||||
|
f, err := os.Create(s.DebugKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Write the key out
|
||||||
|
if _, err := f.Write([]byte(keypair.PrivateKey)); err != nil {
|
||||||
|
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chmod it so that it is SSH ready
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
if err := f.Chmod(0600); err != nil {
|
||||||
|
state.Put("error", fmt.Errorf("Error setting permissions of debug key: %s", err))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we created a temporary key, so remember to clean it up
|
||||||
|
s.doCleanup = true
|
||||||
|
|
||||||
|
// Set some state data for use in future steps
|
||||||
|
s.Comm.SSHKeyPairName = s.Comm.SSHTemporaryKeyPairName
|
||||||
|
s.Comm.SSHPrivateKey = []byte(keypair.PrivateKey)
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Work around for https://github.com/hashicorp/packer/issues/2526
|
||||||
|
func berToDer(ber []byte, ui packersdk.Ui) []byte {
|
||||||
|
// Check if x/crypto/ssh can parse the key
|
||||||
|
_, err := ssh.ParsePrivateKey(ber)
|
||||||
|
if err == nil {
|
||||||
|
return ber
|
||||||
|
}
|
||||||
|
// Can't parse the key, maybe it's BER encoded. Try to convert it with OpenSSL.
|
||||||
|
log.Println("Couldn't parse SSH key, trying work around for [GH-2526].")
|
||||||
|
|
||||||
|
openSslPath, err := exec.LookPath("openssl")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Couldn't find OpenSSL, aborting work around.")
|
||||||
|
return ber
|
||||||
|
}
|
||||||
|
|
||||||
|
berKey, err := tmp.File("packer-ber-privatekey-")
|
||||||
|
defer os.Remove(berKey.Name())
|
||||||
|
if err != nil {
|
||||||
|
return ber
|
||||||
|
}
|
||||||
|
ioutil.WriteFile(berKey.Name(), ber, os.ModeAppend)
|
||||||
|
derKey, err := tmp.File("packer-der-privatekey-")
|
||||||
|
defer os.Remove(derKey.Name())
|
||||||
|
if err != nil {
|
||||||
|
return ber
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{"rsa", "-in", berKey.Name(), "-out", derKey.Name()}
|
||||||
|
log.Printf("Executing: %s %v", openSslPath, args)
|
||||||
|
if err := exec.Command(openSslPath, args...).Run(); err != nil {
|
||||||
|
log.Printf("OpenSSL failed with error: %s", err)
|
||||||
|
return ber
|
||||||
|
}
|
||||||
|
|
||||||
|
der, err := ioutil.ReadFile(derKey.Name())
|
||||||
|
if err != nil {
|
||||||
|
return ber
|
||||||
|
}
|
||||||
|
ui.Say("Successfully converted BER encoded SSH key to DER encoding.")
|
||||||
|
return der
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepKeyPair) Cleanup(state multistep.StateBag) {
|
||||||
|
if !s.doCleanup {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
computeClient, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error cleaning up keypair. Please delete the key manually: %s", s.Comm.SSHTemporaryKeyPairName))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Deleting temporary keypair: %s ...", s.Comm.SSHTemporaryKeyPairName))
|
||||||
|
err = keypairs.Delete(computeClient, s.Comm.SSHTemporaryKeyPairName).ExtractErr()
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error cleaning up keypair. Please delete the key manually: %s", s.Comm.SSHTemporaryKeyPairName))
|
||||||
|
}
|
||||||
|
}
|
63
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_load_flavor.go
generated
vendored
Normal file
63
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_load_flavor.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
|
||||||
|
flavors_utils "github.com/gophercloud/utils/openstack/compute/v2/flavors"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StepLoadFlavor gets the FlavorRef from a Flavor. It first assumes
|
||||||
|
// that the Flavor is a ref and verifies it. Otherwise, it tries to find
|
||||||
|
// the flavor by name.
|
||||||
|
type StepLoadFlavor struct {
|
||||||
|
Flavor string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepLoadFlavor) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
client, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Loading flavor: %s", s.Flavor))
|
||||||
|
log.Printf("[INFO] Loading flavor by ID: %s", s.Flavor)
|
||||||
|
flavor, err := flavors.Get(client, s.Flavor).Extract()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed to find flavor by ID: %s", err)
|
||||||
|
geterr := err
|
||||||
|
|
||||||
|
log.Printf("[INFO] Loading flavor by name: %s", s.Flavor)
|
||||||
|
id, err := flavors_utils.IDFromName(client, s.Flavor)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Failed to find flavor by name: %s", err)
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"Unable to find specified flavor by ID or name!\n\n"+
|
||||||
|
"Error from ID lookup: %s\n\n"+
|
||||||
|
"Error from name lookup: %s",
|
||||||
|
geterr,
|
||||||
|
err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
flavor = &flavors.Flavor{ID: id}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Verified flavor. ID: %s", flavor.ID))
|
||||||
|
state.Put("flavor_id", flavor.ID)
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepLoadFlavor) Cleanup(state multistep.StateBag) {
|
||||||
|
}
|
173
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_run_source_server.go
generated
vendored
Normal file
173
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_run_source_server.go
generated
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepRunSourceServer struct {
|
||||||
|
Name string
|
||||||
|
SecurityGroups []string
|
||||||
|
AvailabilityZone string
|
||||||
|
UserData string
|
||||||
|
UserDataFile string
|
||||||
|
ConfigDrive bool
|
||||||
|
InstanceMetadata map[string]string
|
||||||
|
UseBlockStorageVolume bool
|
||||||
|
ForceDelete bool
|
||||||
|
server *servers.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepRunSourceServer) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
flavor := state.Get("flavor_id").(string)
|
||||||
|
sourceImage := state.Get("source_image").(string)
|
||||||
|
networks := state.Get("networks").([]servers.Network)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
computeClient, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
userData := []byte(s.UserData)
|
||||||
|
if s.UserDataFile != "" {
|
||||||
|
userData, err = ioutil.ReadFile(s.UserDataFile)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error reading user data file: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Launching server...")
|
||||||
|
|
||||||
|
serverOpts := servers.CreateOpts{
|
||||||
|
Name: s.Name,
|
||||||
|
ImageRef: sourceImage,
|
||||||
|
FlavorRef: flavor,
|
||||||
|
SecurityGroups: s.SecurityGroups,
|
||||||
|
Networks: networks,
|
||||||
|
AvailabilityZone: s.AvailabilityZone,
|
||||||
|
UserData: userData,
|
||||||
|
ConfigDrive: &s.ConfigDrive,
|
||||||
|
ServiceClient: computeClient,
|
||||||
|
Metadata: s.InstanceMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
var serverOptsExt servers.CreateOptsBuilder
|
||||||
|
|
||||||
|
// Create root volume in the Block Storage service if required.
|
||||||
|
// Add block device mapping v2 to the server create options if required.
|
||||||
|
if s.UseBlockStorageVolume {
|
||||||
|
volume := state.Get("volume_id").(string)
|
||||||
|
blockDeviceMappingV2 := []bootfromvolume.BlockDevice{
|
||||||
|
{
|
||||||
|
BootIndex: 0,
|
||||||
|
DestinationType: bootfromvolume.DestinationVolume,
|
||||||
|
SourceType: bootfromvolume.SourceVolume,
|
||||||
|
UUID: volume,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// ImageRef and block device mapping is an invalid options combination.
|
||||||
|
serverOpts.ImageRef = ""
|
||||||
|
serverOptsExt = bootfromvolume.CreateOptsExt{
|
||||||
|
CreateOptsBuilder: serverOpts,
|
||||||
|
BlockDevice: blockDeviceMappingV2,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
serverOptsExt = serverOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add keypair to the server create options.
|
||||||
|
keyName := config.Comm.SSHKeyPairName
|
||||||
|
if keyName != "" {
|
||||||
|
serverOptsExt = keypairs.CreateOptsExt{
|
||||||
|
CreateOptsBuilder: serverOptsExt,
|
||||||
|
KeyName: keyName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Launching server...")
|
||||||
|
s.server, err = servers.Create(computeClient, serverOptsExt).Extract()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error launching source server: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Server ID: %s", s.server.ID))
|
||||||
|
log.Printf("server id: %s", s.server.ID)
|
||||||
|
|
||||||
|
ui.Say("Waiting for server to become ready...")
|
||||||
|
stateChange := StateChangeConf{
|
||||||
|
Pending: []string{"BUILD"},
|
||||||
|
Target: []string{"ACTIVE"},
|
||||||
|
Refresh: ServerStateRefreshFunc(computeClient, s.server),
|
||||||
|
StepState: state,
|
||||||
|
}
|
||||||
|
latestServer, err := WaitForState(&stateChange)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error waiting for server (%s) to become ready: %s", s.server.ID, err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
s.server = latestServer.(*servers.Server)
|
||||||
|
state.Put("server", s.server)
|
||||||
|
// instance_id is the generic term used so that users can have access to the
|
||||||
|
// instance id inside of the provisioners, used in step_provision.
|
||||||
|
state.Put("instance_id", s.server.ID)
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepRunSourceServer) Cleanup(state multistep.StateBag) {
|
||||||
|
if s.server == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
computeClient, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Error terminating server, may still be around: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Terminating the source server: %s ...", s.server.ID))
|
||||||
|
if config.ForceDelete {
|
||||||
|
if err := servers.ForceDelete(computeClient, s.server.ID).ExtractErr(); err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Error terminating server, may still be around: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := servers.Delete(computeClient, s.server.ID).ExtractErr(); err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Error terminating server, may still be around: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stateChange := StateChangeConf{
|
||||||
|
Pending: []string{"ACTIVE", "BUILD", "REBUILD", "SUSPENDED", "SHUTOFF", "STOPPED"},
|
||||||
|
Refresh: ServerStateRefreshFunc(computeClient, s.server),
|
||||||
|
Target: []string{"DELETED"},
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitForState(&stateChange)
|
||||||
|
}
|
201
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_source_image_info.go
generated
vendored
Normal file
201
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_source_image_info.go
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/imageimport"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepSourceImageInfo struct {
|
||||||
|
SourceImage string
|
||||||
|
SourceImageName string
|
||||||
|
ExternalSourceImageURL string
|
||||||
|
ExternalSourceImageFormat string
|
||||||
|
ExternalSourceImageProperties map[string]string
|
||||||
|
SourceImageOpts images.ListOpts
|
||||||
|
SourceMostRecent bool
|
||||||
|
SourceProperties map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func PropertiesSatisfied(image *images.Image, props *map[string]string) bool {
|
||||||
|
for key, value := range *props {
|
||||||
|
if image.Properties[key] != value {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepSourceImageInfo) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
client, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("error creating image client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ExternalSourceImageURL != "" {
|
||||||
|
createOpts := images.CreateOpts{
|
||||||
|
Name: s.SourceImageName,
|
||||||
|
ContainerFormat: "bare",
|
||||||
|
DiskFormat: s.ExternalSourceImageFormat,
|
||||||
|
Properties: s.ExternalSourceImageProperties,
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Creating image using external source image with name " + s.SourceImageName)
|
||||||
|
ui.Say("Using disk format " + s.ExternalSourceImageFormat)
|
||||||
|
image, err := images.Create(client, createOpts).Extract()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error creating source image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Created image with ID " + image.ID)
|
||||||
|
|
||||||
|
importOpts := imageimport.CreateOpts{
|
||||||
|
Name: imageimport.WebDownloadMethod,
|
||||||
|
URI: s.ExternalSourceImageURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Importing External Source Image from URL " + s.ExternalSourceImageURL)
|
||||||
|
err = imageimport.Create(client, image.ID, importOpts).ExtractErr()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error importing source image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
for image.Status != images.ImageStatusActive {
|
||||||
|
ui.Message("Image not Active, retrying in 10 seconds")
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
|
||||||
|
img, err := images.Get(client, image.ID).Extract()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error querying image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
image = img
|
||||||
|
}
|
||||||
|
|
||||||
|
s.SourceImage = image.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.SourceImage != "" {
|
||||||
|
state.Put("source_image", s.SourceImage)
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.SourceImageName != "" {
|
||||||
|
s.SourceImageOpts = images.ListOpts{
|
||||||
|
Name: s.SourceImageName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Using Image Filters %+v", s.SourceImageOpts)
|
||||||
|
image := &images.Image{}
|
||||||
|
count := 0
|
||||||
|
err = images.List(client, s.SourceImageOpts).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
imgs, err := images.ExtractImages(page)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, img := range imgs {
|
||||||
|
// Check if all Properties are satisfied
|
||||||
|
if PropertiesSatisfied(&img, &s.SourceProperties) {
|
||||||
|
count++
|
||||||
|
if count == 1 {
|
||||||
|
// Tentatively return this result.
|
||||||
|
*image = img
|
||||||
|
}
|
||||||
|
// Don't iterate over entries we will never use.
|
||||||
|
if count > 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch count {
|
||||||
|
case 0: // Continue looking at next page.
|
||||||
|
return true, nil
|
||||||
|
case 1: // Maybe we're done, maybe there is another result in a later page and it is an error.
|
||||||
|
if s.SourceMostRecent {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
default: // By now we should know if getting 2+ results is an error or not.
|
||||||
|
if s.SourceMostRecent {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf(
|
||||||
|
"Your query returned more than one result. Please try a more specific search, or set most_recent to true. Search filters: %+v properties %+v",
|
||||||
|
s.SourceImageOpts, s.SourceProperties)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error querying image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
if image.ID == "" {
|
||||||
|
err := fmt.Errorf("No image was found matching filters: %+v properties %+v",
|
||||||
|
s.SourceImageOpts, s.SourceProperties)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Found Image ID: %s", image.ID))
|
||||||
|
|
||||||
|
state.Put("source_image", image.ID)
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepSourceImageInfo) Cleanup(state multistep.StateBag) {
|
||||||
|
if s.ExternalSourceImageURL != "" {
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
client, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("error creating image client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Deleting temporary external source image: %s ...", s.SourceImageName))
|
||||||
|
err = images.Delete(client, s.SourceImage).ExtractErr()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("error cleaning up external source image: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_stop_server.go
generated
vendored
Normal file
59
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_stop_server.go
generated
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/startstop"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepStopServer struct{}
|
||||||
|
|
||||||
|
func (s *StepStopServer) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
server := state.Get("server").(*servers.Server)
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
client, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Stopping server: %s ...", server.ID))
|
||||||
|
if err := startstop.Stop(client, server.ID).ExtractErr(); err != nil {
|
||||||
|
if _, ok := err.(gophercloud.ErrDefault409); ok {
|
||||||
|
// The server might have already been shut down by Windows Sysprep
|
||||||
|
log.Printf("[WARN] 409 on stopping an already stopped server, continuing")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("Error stopping server: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Waiting for server to stop: %s ...", server.ID))
|
||||||
|
stateChange := StateChangeConf{
|
||||||
|
Pending: []string{"ACTIVE"},
|
||||||
|
Target: []string{"SHUTOFF", "STOPPED"},
|
||||||
|
Refresh: ServerStateRefreshFunc(client, server),
|
||||||
|
StepState: state,
|
||||||
|
}
|
||||||
|
if _, err := WaitForState(&stateChange); err != nil {
|
||||||
|
err := fmt.Errorf("Error waiting for server (%s) to stop: %s", server.ID, err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepStopServer) Cleanup(state multistep.StateBag) {}
|
58
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_update_image_mindisk.go
generated
vendored
Normal file
58
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_update_image_mindisk.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stepUpdateImageMinDisk struct{}
|
||||||
|
|
||||||
|
func (s *stepUpdateImageMinDisk) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
|
||||||
|
if config.SkipCreateImage {
|
||||||
|
ui.Say("Skipping image update mindisk...")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
imageId := state.Get("image").(string)
|
||||||
|
|
||||||
|
if config.ImageMinDisk == 0 {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
imageClient, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error initializing image service client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Updating image min disk to %d", config.ImageMinDisk))
|
||||||
|
|
||||||
|
r := images.Update(
|
||||||
|
imageClient,
|
||||||
|
imageId,
|
||||||
|
images.UpdateOpts{
|
||||||
|
images.ReplaceImageMinDisk{
|
||||||
|
NewMinDisk: config.ImageMinDisk,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if _, err := r.Extract(); err != nil {
|
||||||
|
err = fmt.Errorf("Error updating image min disk: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepUpdateImageMinDisk) Cleanup(multistep.StateBag) {
|
||||||
|
// No cleanup...
|
||||||
|
}
|
58
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_update_image_tags.go
generated
vendored
Normal file
58
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_update_image_tags.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
imageservice "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stepUpdateImageTags struct{}
|
||||||
|
|
||||||
|
func (s *stepUpdateImageTags) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
|
||||||
|
if config.SkipCreateImage {
|
||||||
|
ui.Say("Skipping image update tags...")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
imageId := state.Get("image").(string)
|
||||||
|
|
||||||
|
if len(config.ImageTags) == 0 {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
imageClient, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing image service client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Updating image tags to %s", strings.Join(config.ImageTags, ", ")))
|
||||||
|
r := imageservice.Update(
|
||||||
|
imageClient,
|
||||||
|
imageId,
|
||||||
|
imageservice.UpdateOpts{
|
||||||
|
imageservice.ReplaceImageTags{
|
||||||
|
NewTags: config.ImageTags,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if _, err = r.Extract(); err != nil {
|
||||||
|
err = fmt.Errorf("Error updating image tags: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepUpdateImageTags) Cleanup(multistep.StateBag) {
|
||||||
|
// No cleanup...
|
||||||
|
}
|
57
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_update_image_visibility.go
generated
vendored
Normal file
57
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_update_image_visibility.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
imageservice "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stepUpdateImageVisibility struct{}
|
||||||
|
|
||||||
|
func (s *stepUpdateImageVisibility) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
|
||||||
|
if config.SkipCreateImage {
|
||||||
|
ui.Say("Skipping image update visibility...")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
imageId := state.Get("image").(string)
|
||||||
|
|
||||||
|
if config.ImageVisibility == "" {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
imageClient, err := config.imageV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing image service client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Updating image visibility to %s", config.ImageVisibility))
|
||||||
|
r := imageservice.Update(
|
||||||
|
imageClient,
|
||||||
|
imageId,
|
||||||
|
imageservice.UpdateOpts{
|
||||||
|
imageservice.UpdateVisibility{
|
||||||
|
Visibility: config.ImageVisibility,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if _, err = r.Extract(); err != nil {
|
||||||
|
err = fmt.Errorf("Error updating image visibility: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepUpdateImageVisibility) Cleanup(multistep.StateBag) {
|
||||||
|
// No cleanup...
|
||||||
|
}
|
54
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_wait_for_rackconnect.go
generated
vendored
Normal file
54
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/step_wait_for_rackconnect.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepWaitForRackConnect struct {
|
||||||
|
Wait bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepWaitForRackConnect) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
if !s.Wait {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
server := state.Get("server").(*servers.Server)
|
||||||
|
ui := state.Get("ui").(packersdk.Ui)
|
||||||
|
|
||||||
|
// We need the v2 compute client
|
||||||
|
computeClient, err := config.computeV2Client()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf(
|
||||||
|
"Waiting for server (%s) to become RackConnect ready...", server.ID))
|
||||||
|
for {
|
||||||
|
server, err = servers.Get(computeClient, server.ID).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
if server.Metadata["rackconnect_automation_status"] == "DEPLOYED" {
|
||||||
|
state.Put("server", server)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepWaitForRackConnect) Cleanup(state multistep.StateBag) {
|
||||||
|
}
|
76
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/volume.go
generated
vendored
Normal file
76
vendor/github.com/hashicorp/packer-plugin-openstack/builder/openstack/volume.go
generated
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WaitForVolume waits for the given volume to become available.
|
||||||
|
func WaitForVolume(blockStorageClient *gophercloud.ServiceClient, volumeID string) error {
|
||||||
|
maxNumErrors := 10
|
||||||
|
numErrors := 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
status, err := GetVolumeStatus(blockStorageClient, volumeID)
|
||||||
|
if err != nil {
|
||||||
|
errCode, ok := err.(*gophercloud.ErrUnexpectedResponseCode)
|
||||||
|
if ok && (errCode.Actual == 500 || errCode.Actual == 404) {
|
||||||
|
numErrors++
|
||||||
|
if numErrors >= maxNumErrors {
|
||||||
|
log.Printf("[ERROR] Maximum number of errors (%d) reached; failing with: %s", numErrors, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[ERROR] %d error received, will ignore and retry: %s", errCode.Actual, err)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == "available" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Waiting for volume creation status: %s", status)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVolumeSize returns volume size in gigabytes based on the image min disk
|
||||||
|
// value if it's not empty.
|
||||||
|
// Or it calculates needed gigabytes size from the image bytes size.
|
||||||
|
func GetVolumeSize(imageClient *gophercloud.ServiceClient, imageID string) (int, error) {
|
||||||
|
sourceImage, err := images.Get(imageClient, imageID).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sourceImage.MinDiskGigabytes != 0 {
|
||||||
|
return sourceImage.MinDiskGigabytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
volumeSizeMB := sourceImage.SizeBytes / 1024 / 1024
|
||||||
|
volumeSizeGB := int(sourceImage.SizeBytes / 1024 / 1024 / 1024)
|
||||||
|
|
||||||
|
// Increment gigabytes size if the initial size can't be divided without
|
||||||
|
// remainder.
|
||||||
|
if volumeSizeMB%1024 > 0 {
|
||||||
|
volumeSizeGB++
|
||||||
|
}
|
||||||
|
|
||||||
|
return volumeSizeGB, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVolumeStatus(blockStorageClient *gophercloud.ServiceClient, volumeID string) (string, error) {
|
||||||
|
volume, err := volumes.Get(blockStorageClient, volumeID).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return volume.Status, nil
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ go:
|
||||||
- "1.11.x"
|
- "1.11.x"
|
||||||
- "1.12.x"
|
- "1.12.x"
|
||||||
- "1.13.x"
|
- "1.13.x"
|
||||||
|
- "1.14.x"
|
||||||
- "tip"
|
- "tip"
|
||||||
|
|
||||||
go_import_path: gopkg.in/yaml.v2
|
go_import_path: gopkg.in/yaml.v2
|
||||||
|
|
|
@ -79,6 +79,8 @@ func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
|
||||||
parser.encoding = encoding
|
parser.encoding = encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var disableLineWrapping = false
|
||||||
|
|
||||||
// Create a new emitter object.
|
// Create a new emitter object.
|
||||||
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
|
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
|
||||||
*emitter = yaml_emitter_t{
|
*emitter = yaml_emitter_t{
|
||||||
|
@ -86,7 +88,9 @@ func yaml_emitter_initialize(emitter *yaml_emitter_t) {
|
||||||
raw_buffer: make([]byte, 0, output_raw_buffer_size),
|
raw_buffer: make([]byte, 0, output_raw_buffer_size),
|
||||||
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
|
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
|
||||||
events: make([]yaml_event_t, 0, initial_queue_size),
|
events: make([]yaml_event_t, 0, initial_queue_size),
|
||||||
best_width: -1,
|
}
|
||||||
|
if disableLineWrapping {
|
||||||
|
emitter.best_width = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module "gopkg.in/yaml.v2"
|
module gopkg.in/yaml.v2
|
||||||
|
|
||||||
require (
|
go 1.15
|
||||||
"gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
|
|
||||||
)
|
require gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
|
||||||
|
|
|
@ -175,7 +175,7 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
|
||||||
// Zero valued structs will be omitted if all their public
|
// Zero valued structs will be omitted if all their public
|
||||||
// fields are zero, unless they implement an IsZero
|
// fields are zero, unless they implement an IsZero
|
||||||
// method (see the IsZeroer interface type), in which
|
// method (see the IsZeroer interface type), in which
|
||||||
// case the field will be included if that method returns true.
|
// case the field will be excluded if IsZero returns true.
|
||||||
//
|
//
|
||||||
// flow Marshal using a flow style (useful for structs,
|
// flow Marshal using a flow style (useful for structs,
|
||||||
// sequences and maps).
|
// sequences and maps).
|
||||||
|
@ -464,3 +464,15 @@ func isZero(v reflect.Value) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FutureLineWrap globally disables line wrapping when encoding long strings.
|
||||||
|
// This is a temporary and thus deprecated method introduced to faciliate
|
||||||
|
// migration towards v3, which offers more control of line lengths on
|
||||||
|
// individual encodings, and has a default matching the behavior introduced
|
||||||
|
// by this function.
|
||||||
|
//
|
||||||
|
// The default formatting of v2 was erroneously changed in v2.3.0 and reverted
|
||||||
|
// in v2.4.0, at which point this function was introduced to help migration.
|
||||||
|
func FutureLineWrap() {
|
||||||
|
disableLineWrapping = true
|
||||||
|
}
|
||||||
|
|
|
@ -525,6 +525,9 @@ github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-im
|
||||||
# github.com/hashicorp/packer-plugin-ncloud v0.0.2
|
# github.com/hashicorp/packer-plugin-ncloud v0.0.2
|
||||||
## explicit
|
## explicit
|
||||||
github.com/hashicorp/packer-plugin-ncloud/builder/ncloud
|
github.com/hashicorp/packer-plugin-ncloud/builder/ncloud
|
||||||
|
# github.com/hashicorp/packer-plugin-openstack v0.0.1
|
||||||
|
## explicit
|
||||||
|
github.com/hashicorp/packer-plugin-openstack/builder/openstack
|
||||||
# github.com/hashicorp/packer-plugin-outscale v0.0.1
|
# github.com/hashicorp/packer-plugin-outscale v0.0.1
|
||||||
## explicit
|
## explicit
|
||||||
github.com/hashicorp/packer-plugin-outscale/builder/osc/bsu
|
github.com/hashicorp/packer-plugin-outscale/builder/osc/bsu
|
||||||
|
@ -1210,7 +1213,7 @@ gopkg.in/square/go-jose.v2
|
||||||
gopkg.in/square/go-jose.v2/cipher
|
gopkg.in/square/go-jose.v2/cipher
|
||||||
gopkg.in/square/go-jose.v2/json
|
gopkg.in/square/go-jose.v2/json
|
||||||
gopkg.in/square/go-jose.v2/jwt
|
gopkg.in/square/go-jose.v2/jwt
|
||||||
# gopkg.in/yaml.v2 v2.3.0
|
# gopkg.in/yaml.v2 v2.4.0
|
||||||
gopkg.in/yaml.v2
|
gopkg.in/yaml.v2
|
||||||
# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||||
gopkg.in/yaml.v3
|
gopkg.in/yaml.v3
|
||||||
|
|
|
@ -753,10 +753,6 @@
|
||||||
"title": "1&1",
|
"title": "1&1",
|
||||||
"path": "builders/oneandone"
|
"path": "builders/oneandone"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"title": "OpenStack",
|
|
||||||
"path": "builders/openstack"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"title": "Oracle",
|
"title": "Oracle",
|
||||||
"routes": [
|
"routes": [
|
||||||
|
|
|
@ -37,6 +37,26 @@
|
||||||
"pluginTier": "community",
|
"pluginTier": "community",
|
||||||
"version": "latest"
|
"version": "latest"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "Openstack",
|
||||||
|
"path": "openstack",
|
||||||
|
"repo": "hashicorp/packer-plugin-openstack",
|
||||||
|
"pluginTier": "community",
|
||||||
|
"version": "latest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Outscale",
|
||||||
|
"path": "outscale",
|
||||||
|
"repo": "hashicorp/packer-plugin-outscale",
|
||||||
|
"version": "latest",
|
||||||
|
"pluginTier": "community"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Parallels",
|
||||||
|
"path": "parallels",
|
||||||
|
"repo": "hashicorp/packer-plugin-parallels",
|
||||||
|
"version": "latest"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "Proxmox",
|
"title": "Proxmox",
|
||||||
"path": "proxmox",
|
"path": "proxmox",
|
||||||
|
@ -74,18 +94,5 @@
|
||||||
"path": "qemu",
|
"path": "qemu",
|
||||||
"repo": "hashicorp/packer-plugin-qemu",
|
"repo": "hashicorp/packer-plugin-qemu",
|
||||||
"version": "latest"
|
"version": "latest"
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Outscale",
|
|
||||||
"path": "outscale",
|
|
||||||
"repo": "hashicorp/packer-plugin-outscale",
|
|
||||||
"version": "latest",
|
|
||||||
"pluginTier": "community"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Parallels",
|
|
||||||
"path": "parallels",
|
|
||||||
"repo": "hashicorp/packer-plugin-parallels",
|
|
||||||
"version": "latest"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue