Skip to content

Commit f8d433c

Browse files
author
Radoslav Mirchev
committed
terraform 0.12.x support
1 parent decb0a0 commit f8d433c

File tree

337 files changed

+71675
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

337 files changed

+71675
-1
lines changed

CHANGELOG.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## 0.3.0
2+
New version supporting new Terraform API version 5
3+
* The whole provider was re-build around teeraform source code for version 0.12.x+
4+
which add support (and makes possible to run the provider) on Terraform 0.12.x+
5+
6+
## 0.2.0
7+
8+
New version with some breaking changes regarding custom fields:
9+
10+
* Custom field searches are not done via the `custom_field_filter` attribute in
11+
both the `phpipam_address` and `phpipam_subnet` data sources. This parameter
12+
is a map that takes custom field names, and regular expressions to search for
13+
against. A field does not match if any of the search criteria keys are
14+
missing or do not match.
15+
16+
Also have added two new data sources:
17+
18+
* `phpipam_address` will search addresses for a `description` or `hostname`
19+
exact match or a `custom_field_filter` match, much like the singular-form
20+
`phpipam_address` data source. A list of IP address IDs are returned, which
21+
can then be used to look up addresses with the `phpipam_address` data source.
22+
This will work better in Terraform v0.9.x, or higher, which has support for a
23+
computed `count` in data sources now.
24+
* `phpipam_subnets` has been added in the same way. This one can search on
25+
`description`, `description_match`, and `custom_field_filter`, in the same
26+
way the singular-form `phpipam_address` data source can.
27+
28+
## 0.1.2
29+
30+
Added custom field support - this plugin now supports custom fields in
31+
addresses, subnets, and VLANs, as long as those fields are optional. Data source
32+
searching supports addresses and subnets only, due to limitations in VLAN
33+
searching capabilities.
34+
35+
## 0.1.1
36+
37+
Bumping release so that I have a consistent snapshot, and also so that I can
38+
correct some tests on the compat branch.
39+
40+
## 0.1.0
41+
42+
First release!

LICENSE

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2017 PayByPhone Technologies, Inc.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

Makefile

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
test:
2+
go test -v $(shell go list ./... | grep -v /vendor/)
3+
4+
testacc:
5+
TF_ACC=1 go test -v ./plugin/providers/phpipam -run="TestAcc"
6+
7+
build: deps
8+
gox -osarch="linux/amd64 windows/amd64 darwin/amd64" \
9+
-output="pkg/{{.OS}}_{{.Arch}}/terraform-provider-phpipam" .
10+
11+
release: release_bump release_build
12+
13+
release_bump:
14+
scripts/release_bump.sh
15+
16+
release_build:
17+
scripts/release_build.sh
18+
19+
deps:
20+
go get -u github.com/mitchellh/gox
21+
22+
clean:
23+
rm -rf pkg/

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# ATTENTION!!!
2-
This repository is based on the original work of github user babyphone.
2+
This repository is based on the original work of github user paybyphone.
33
However, the version of the provider in this repo is updated and revised to support working with Terraform 12.x+
44
The build here is currently based on the babyphone original repo + hashicorp original terraform repo and was build around Terraform version 0.12.11
55
All credit should go to https://github.com/paybyphone/terraform-provider-phpipam - I've just modernized his work!

main.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package main
2+
3+
import (
4+
"github.com/hashicorp/terraform/plugin"
5+
"github.com/paybyphone/terraform-provider-phpipam/plugin/providers/phpipam"
6+
)
7+
8+
func main() {
9+
plugin.Serve(&plugin.ServeOpts{
10+
ProviderFunc: phpipam.Provider,
11+
})
12+
}

main_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform/plugin"
7+
)
8+
9+
// pluginVersionExpected provides the expected plugin version that this release
10+
// of the plugin is built with.
11+
const pluginVersionExpected = 4
12+
13+
// TestPluginVersion tests the plugin API version of the vendored Terraform
14+
// libraries.
15+
func TestPluginVersion(t *testing.T) {
16+
if plugin.Handshake.ProtocolVersion != pluginVersionExpected {
17+
t.Fatalf("Expected vendored plugin version to be %d, got %d", pluginVersionExpected, plugin.Handshake.ProtocolVersion)
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
package phpipam
2+
3+
import (
4+
"errors"
5+
"strconv"
6+
7+
"github.com/hashicorp/terraform/helper/schema"
8+
"github.com/paybyphone/phpipam-sdk-go/controllers/addresses"
9+
"github.com/paybyphone/phpipam-sdk-go/phpipam"
10+
)
11+
12+
// resourceAddressOptionalFields represents all the fields that are optional in
13+
// the phpipam_address resource. These fields get flagged as Optional, with zero
14+
// value defaults (the field is not set), in addition to being marked as
15+
// Computed. Any field not listed here cannot be supplied by the resource and
16+
// is solely computed.
17+
var resourceAddressOptionalFields = linearSearchSlice{
18+
"is_gateway",
19+
"description",
20+
"hostname",
21+
"mac_address",
22+
"owner",
23+
"state_tag_id",
24+
"skip_ptr_record",
25+
"ptr_record_id",
26+
"device_id",
27+
"switch_port_label",
28+
"note",
29+
"exclude_ping",
30+
}
31+
32+
// bareAddressSchema returns a map[string]*schema.Schema with the schema used
33+
// to represent a PHPIPAM address resource. This output should then be modified
34+
// so that required and computed fields are set properly for both the data
35+
// source and the resource.
36+
func bareAddressSchema() map[string]*schema.Schema {
37+
return map[string]*schema.Schema{
38+
"address_id": &schema.Schema{
39+
Type: schema.TypeInt,
40+
},
41+
"subnet_id": &schema.Schema{
42+
Type: schema.TypeInt,
43+
},
44+
"ip_address": &schema.Schema{
45+
Type: schema.TypeString,
46+
},
47+
"is_gateway": &schema.Schema{
48+
Type: schema.TypeBool,
49+
},
50+
"description": &schema.Schema{
51+
Type: schema.TypeString,
52+
},
53+
"hostname": &schema.Schema{
54+
Type: schema.TypeString,
55+
},
56+
"mac_address": &schema.Schema{
57+
Type: schema.TypeString,
58+
},
59+
"owner": &schema.Schema{
60+
Type: schema.TypeString,
61+
},
62+
"state_tag_id": &schema.Schema{
63+
Type: schema.TypeInt,
64+
},
65+
"skip_ptr_record": &schema.Schema{
66+
Type: schema.TypeBool,
67+
},
68+
"ptr_record_id": &schema.Schema{
69+
Type: schema.TypeInt,
70+
},
71+
"device_id": &schema.Schema{
72+
Type: schema.TypeInt,
73+
},
74+
"switch_port_label": &schema.Schema{
75+
Type: schema.TypeString,
76+
},
77+
"note": &schema.Schema{
78+
Type: schema.TypeString,
79+
},
80+
"last_seen": &schema.Schema{
81+
Type: schema.TypeString,
82+
},
83+
"exclude_ping": &schema.Schema{
84+
Type: schema.TypeBool,
85+
},
86+
"edit_date": &schema.Schema{
87+
Type: schema.TypeString,
88+
},
89+
"custom_fields": &schema.Schema{
90+
Type: schema.TypeMap,
91+
},
92+
}
93+
}
94+
95+
// resourceAddressSchema returns the schema for the phpipam_address resource.
96+
// It sets the required and optional fields, the latter defined in
97+
// resourceAddressRequiredFields, and ensures that all optional and
98+
// non-configurable fields are computed as well.
99+
func resourceAddressSchema() map[string]*schema.Schema {
100+
s := bareAddressSchema()
101+
for k, v := range s {
102+
switch {
103+
// IP Address and Subnet ID are ForceNew
104+
case k == "subnet_id" || k == "ip_address":
105+
v.Required = true
106+
v.ForceNew = true
107+
case k == "custom_fields":
108+
v.Optional = true
109+
case resourceAddressOptionalFields.Has(k):
110+
v.Optional = true
111+
v.Computed = true
112+
default:
113+
v.Computed = true
114+
}
115+
}
116+
// Add the remove_dns_on_delete item to the schema. This is a meta-parameter
117+
// that is not part of the API resource and exists to instruct PHPIPAM to
118+
// gracefully remove the address from its DNS integrations as well when it is
119+
// removed. The default on this option is true.
120+
s["remove_dns_on_delete"] = &schema.Schema{
121+
Type: schema.TypeBool,
122+
Optional: true,
123+
Default: true,
124+
}
125+
return s
126+
}
127+
128+
// dataSourceAddressSchema returns the schema for the phpipam_address data
129+
// source. It sets the searchable fields and sets up the attribute conflicts
130+
// between IP address and address ID. It also ensures that all fields are
131+
// computed as well.
132+
func dataSourceAddressSchema() map[string]*schema.Schema {
133+
s := bareAddressSchema()
134+
for k, v := range s {
135+
switch k {
136+
case "address_id":
137+
v.Optional = true
138+
v.Computed = true
139+
v.ConflictsWith = []string{"ip_address", "subnet_id", "description", "hostname", "custom_field_filter"}
140+
case "ip_address":
141+
v.Optional = true
142+
v.Computed = true
143+
v.ConflictsWith = []string{"address_id", "subnet_id", "description", "hostname", "custom_field_filter"}
144+
case "subnet_id":
145+
v.Optional = true
146+
v.Computed = true
147+
v.ConflictsWith = []string{"ip_address", "address_id"}
148+
case "description":
149+
v.Optional = true
150+
v.Computed = true
151+
v.ConflictsWith = []string{"ip_address", "address_id", "hostname", "custom_field_filter"}
152+
case "hostname":
153+
v.Optional = true
154+
v.Computed = true
155+
v.ConflictsWith = []string{"ip_address", "address_id", "description", "custom_field_filter"}
156+
default:
157+
v.Computed = true
158+
}
159+
}
160+
// Add the custom_field_filter item to the schema. This is a meta-parameter
161+
// that allows searching for a custom field value in the data source.
162+
s["custom_field_filter"] = customFieldFilterSchema([]string{"ip_address", "address_id", "hostname", "description"})
163+
164+
return s
165+
}
166+
167+
// expandAddress returns the addresses.Address structure for a
168+
// phpiapm_address resource or data source. Depending on if we are dealing with
169+
// the resource or data source, extra considerations may need to be taken.
170+
func expandAddress(d *schema.ResourceData) addresses.Address {
171+
s := addresses.Address{
172+
ID: d.Get("address_id").(int),
173+
SubnetID: d.Get("subnet_id").(int),
174+
IPAddress: d.Get("ip_address").(string),
175+
IsGateway: phpipam.BoolIntString(d.Get("is_gateway").(bool)),
176+
Description: d.Get("description").(string),
177+
Hostname: d.Get("hostname").(string),
178+
MACAddress: d.Get("mac_address").(string),
179+
Owner: d.Get("owner").(string),
180+
Tag: d.Get("state_tag_id").(int),
181+
PTRIgnore: phpipam.BoolIntString(d.Get("skip_ptr_record").(bool)),
182+
PTRRecordID: d.Get("ptr_record_id").(int),
183+
DeviceID: d.Get("device_id").(int),
184+
Port: d.Get("switch_port_label").(string),
185+
Note: d.Get("note").(string),
186+
LastSeen: d.Get("last_seen").(string),
187+
ExcludePing: phpipam.BoolIntString(d.Get("exclude_ping").(bool)),
188+
}
189+
190+
return s
191+
}
192+
193+
// flattenAddress sets fields in a *schema.ResourceData with fields supplied by
194+
// the input addresses.Address. This is used in read operations.
195+
func flattenAddress(a addresses.Address, d *schema.ResourceData) {
196+
d.SetId(strconv.Itoa(a.ID))
197+
d.Set("address_id", a.ID)
198+
d.Set("subnet_id", a.SubnetID)
199+
d.Set("ip_address", a.IPAddress)
200+
d.Set("is_gateway", a.IsGateway)
201+
d.Set("description", a.Description)
202+
d.Set("hostname", a.Hostname)
203+
d.Set("mac_address", a.MACAddress)
204+
d.Set("owner", a.Owner)
205+
d.Set("state_tag_id", a.Tag)
206+
d.Set("skip_ptr_record", a.PTRIgnore)
207+
d.Set("ptr_record_id", a.PTRRecordID)
208+
d.Set("device_id", a.DeviceID)
209+
d.Set("switch_port_label", a.Port)
210+
d.Set("note", a.Note)
211+
d.Set("last_seen", a.LastSeen)
212+
d.Set("exclude_ping", a.ExcludePing)
213+
d.Set("edit_date", a.EditDate)
214+
}
215+
216+
// addressSearchInSubnet provides the address search functionality for both the
217+
// phpipam_address and phpipam_addresses data sources, returning an
218+
// []addresses.Address to the particular data source that is calling the
219+
// function. From here it's up to the specific data source to determine what
220+
// they want to do with the results (ie: reject it on matching nothing or more
221+
// than one for the singular data source, or extracting the IDs for the plural
222+
// one).
223+
func addressSearchInSubnet(d *schema.ResourceData, meta interface{}) ([]addresses.Address, error) {
224+
c := meta.(*ProviderPHPIPAMClient).addressesController
225+
s := meta.(*ProviderPHPIPAMClient).subnetsController
226+
result := make([]addresses.Address, 0)
227+
v, err := s.GetAddressesInSubnet(d.Get("subnet_id").(int))
228+
if err != nil {
229+
return result, err
230+
}
231+
if len(v) == 0 {
232+
return result, errors.New("No addresses were found in the supplied subnet")
233+
}
234+
for _, r := range v {
235+
switch {
236+
// Double-assert that we don't have empty strings in the conditionals
237+
// to ensure there there is no edge cases with matching zero values.
238+
case d.Get("description").(string) != "" && r.Description == d.Get("description").(string):
239+
result = append(result, r)
240+
case d.Get("hostname").(string) != "" && r.Hostname == d.Get("hostname").(string):
241+
result = append(result, r)
242+
case len(d.Get("custom_field_filter").(map[string]interface{})) > 0:
243+
fields, err := c.GetAddressCustomFields(r.ID)
244+
if err != nil {
245+
return result, err
246+
}
247+
search := d.Get("custom_field_filter").(map[string]interface{})
248+
matched, err := customFieldFilter(fields, search)
249+
if err != nil {
250+
return result, err
251+
}
252+
if matched {
253+
result = append(result, r)
254+
}
255+
}
256+
}
257+
return result, nil
258+
}

0 commit comments

Comments
 (0)