Skip to content

Commit

Permalink
Add user_data_url_headers (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven Hardy authored Dec 1, 2020
1 parent 2d20594 commit 8ba6ddd
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 33 deletions.
35 changes: 27 additions & 8 deletions ironic/resource_ironic_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func resourceDeployment() *schema.Resource {
Optional: true,
ForceNew: true,
},
"user_data_url_headers": {
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
},
"network_data": {
Type: schema.TypeMap,
Optional: true,
Expand Down Expand Up @@ -105,9 +110,13 @@ func resourceDeploymentCreate(d *schema.ResourceData, meta interface{}) error {
userData := d.Get("user_data").(string)
userDataURL := d.Get("user_data_url").(string)
userDataCaCert := d.Get("user_data_url_ca_cert").(string)
userDataHeaders := d.Get("user_data_url_headers").(map[string]interface{})

// if user_data_url is specified in addition to user_data, use the former
ignitionData := fetchFullIgnition(userDataURL, userDataCaCert)
ignitionData, err := fetchFullIgnition(userDataURL, userDataCaCert, userDataHeaders)
if err != nil {
return fmt.Errorf("could not fetch data from user_data_url: %s", err)
}
if ignitionData != "" {
userData = ignitionData
}
Expand All @@ -125,7 +134,7 @@ func resourceDeploymentCreate(d *schema.ResourceData, meta interface{}) error {
}

// fetchFullIgnition gets full igntion from the URL and cert passed to it and returns userdata as a string
func fetchFullIgnition(userDataURL string, userDataCaCert string) string {
func fetchFullIgnition(userDataURL string, userDataCaCert string, userDataHeaders map[string]interface{}) (string, error) {
// Send full ignition, if the URL is specified
if userDataURL != "" {
caCertPool := x509.NewCertPool()
Expand All @@ -135,7 +144,7 @@ func fetchFullIgnition(userDataURL string, userDataCaCert string) string {
caCert, err := base64.StdEncoding.DecodeString(userDataCaCert)
if err != nil {
log.Printf("could not decode user_data_url_ca_cert: %s", err)
return ""
return "", err
}
caCertPool.AppendCertsFromPEM(caCert)

Expand All @@ -149,21 +158,31 @@ func fetchFullIgnition(userDataURL string, userDataCaCert string) string {
client.HTTPClient.Transport = transport

// Get the data
resp, err := client.Get(userDataURL)
req, err := retryablehttp.NewRequest("GET", userDataURL, nil)
if err != nil {
log.Printf("could not get user_data_url: %s", err)
return "", err
}
if userDataHeaders != nil {
for k, v := range userDataHeaders {
req.Header.Add(k, v.(string))
}
}
resp, err := client.Do(req)
if err != nil {
log.Printf("could not get user_data_url: %s", err)
return ""
return "", err
}
defer resp.Body.Close()
var userData []byte
userData, err = ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("could not read user_data_url: %s", err)
return ""
return "", err
}
return string(userData)
return string(userData), nil
}
return ""
return "", nil
}

// buildConfigDrive handles building a config drive appropriate for the Ironic version we are using. Newer versions
Expand Down
68 changes: 43 additions & 25 deletions ironic/resource_ironic_deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ func testAccDeploymentResource(node, resourceClass, allocation string) string {
func TestFetchFullIgnition(t *testing.T) {
// Setup a fake https endpoint to server full ignition
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
for k, v := range r.Header {
if k == "Test" {
fmt.Fprintf(w, "Header: %s=%s\n", k, v)
}
}
fmt.Fprintln(w, "Full Ignition")
}))
defer server.Close()
Expand All @@ -131,45 +136,58 @@ func TestFetchFullIgnition(t *testing.T) {
},
)
certB64 := base64.URLEncoding.EncodeToString(certInPem)
emptyHeaders := make(map[string]interface{})

testCases := []struct {
Scenario string
UserDataURL string
UserDataURLCACert string
ExpectResult bool
Scenario string
UserDataURL string
UserDataURLCACert string
UserDataURLHeaders map[string]interface{}
ExpectedResult string
}{
{
Scenario: "user data url and ca cert present",
UserDataURL: server.URL,
UserDataURLCACert: certB64,
ExpectResult: true,
Scenario: "user data url and ca cert present",
UserDataURL: server.URL,
UserDataURLCACert: certB64,
UserDataURLHeaders: emptyHeaders,
ExpectedResult: "Full Ignition\n",
},
{
Scenario: "user data url present but no ca cert",
UserDataURL: server.URL,
UserDataURLCACert: "",
UserDataURLHeaders: emptyHeaders,
ExpectedResult: "Full Ignition\n",
},
{
Scenario: "user data url present but no ca cert",
UserDataURL: server.URL,
UserDataURLCACert: "",
ExpectResult: true,
Scenario: "user data url, ca cert and headers present",
UserDataURL: server.URL,
UserDataURLCACert: certB64,
UserDataURLHeaders: map[string]interface{}{"Test": "foo"},
ExpectedResult: "Header: Test=[foo]\nFull Ignition\n",
},
{
Scenario: "user data url is not present but ca cert is",
UserDataURL: "",
UserDataURLCACert: certB64,
ExpectResult: false,
Scenario: "user data url is not present but ca cert is",
UserDataURL: "",
UserDataURLCACert: certB64,
UserDataURLHeaders: emptyHeaders,
ExpectedResult: "",
},
{
Scenario: "neither user data url nor ca cert is not present",
UserDataURL: "",
UserDataURLCACert: "",
ExpectResult: false,
Scenario: "neither user data url nor ca cert is not present",
UserDataURL: "",
UserDataURLCACert: "",
UserDataURLHeaders: emptyHeaders,
ExpectedResult: "",
},
}
for _, tc := range testCases {
userData := fetchFullIgnition(tc.UserDataURL, tc.UserDataURLCACert)
if tc.ExpectResult && (userData != "Full Ignition\n") {
t.Errorf("expected userData: %s, got %s", "Full Ignition\n", userData)
userData, err := fetchFullIgnition(tc.UserDataURL, tc.UserDataURLCACert, tc.UserDataURLHeaders)
if err != nil {
t.Errorf("expected err: %s", err)
}
if !tc.ExpectResult && (userData != "") {
t.Errorf("expected userData: %s, got %s", "", userData)
if userData != tc.ExpectedResult {
t.Errorf("expected userData: %s, got %s", tc.ExpectedResult, userData)
}
}
}

0 comments on commit 8ba6ddd

Please sign in to comment.