server.garden privileged automation agent (mirror of https://git.sequentialread.com/forest/rootsystem)
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.4 KiB
113 lines
3.4 KiB
package automation |
|
|
|
import ( |
|
"encoding/json" |
|
"fmt" |
|
"io/ioutil" |
|
"net/http" |
|
"strconv" |
|
"strings" |
|
|
|
errors "git.sequentialread.com/forest/pkg-errors" |
|
"git.sequentialread.com/forest/rootsystem/configuration" |
|
) |
|
|
|
type digialOceanSSHKeysResponse struct { |
|
SSHKeys []digitalOceanSSHKey `json:"ssh_keys"` |
|
} |
|
|
|
type digitalOceanSSHKey struct { |
|
Id int `json:"id"` |
|
Fingerprint string `json:"fingerprint"` |
|
PublicKey string `json:"public_key"` |
|
Pame string `json:"name"` |
|
} |
|
|
|
func handleDigitalOceanSSHKeyAlreadyExists( |
|
config *configuration.Configuration, |
|
workingDirectory string, |
|
terraformDirectory string, |
|
tfShow *TerraformShow, |
|
) (bool, error) { |
|
|
|
var digitaloceanCredential *configuration.Credential = nil |
|
for _, cred := range config.Credentials { |
|
if cred.Type == configuration.DIGITALOCEAN { |
|
digitaloceanCredential = &cred |
|
break |
|
} |
|
} |
|
|
|
createSSHKeys := filterResourceChanges( |
|
tfShow, |
|
ResourceChangeFilter{ResourceType: "digitalocean_ssh_key", Action: "create", NotAction: "delete"}, |
|
) |
|
|
|
if digitaloceanCredential == nil || len(createSSHKeys) == 0 { |
|
return false, nil |
|
} |
|
|
|
// createAnySSHKeys |
|
// for _, module := range tfShow.PlannedValues.RootModule.ChildModules { |
|
// for _, resource := range module.Resources { |
|
// if resource.Type == "digitalocean_ssh_key" { |
|
// } |
|
// } |
|
// } |
|
|
|
// Get the ssh public keys from digital ocean API |
|
httpClient := http.Client{} |
|
request, err := http.NewRequest("GET", fmt.Sprintf("%s%s", configuration.DIGITALOCEAN_API_URL, "/v2/account/keys"), nil) |
|
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", digitaloceanCredential.Password)) |
|
response, err := httpClient.Do(request) |
|
if err != nil { |
|
return false, err |
|
} |
|
if response.StatusCode != 200 { |
|
return false, fmt.Errorf("HTTP %d when calling /v2/account/keys on digitalocean API", response.StatusCode) |
|
} |
|
bytes, err := ioutil.ReadAll(response.Body) |
|
if err != nil { |
|
return false, errors.Wrap(err, "HTTP read error when calling /v2/account/keys on digitalocean API") |
|
} |
|
var responseObject digialOceanSSHKeysResponse |
|
err = json.Unmarshal(bytes, &responseObject) |
|
if err != nil { |
|
return false, errors.Wrap(err, "JSON parse error when calling /v2/account/keys on digitalocean API") |
|
} |
|
|
|
digitalOceanIdByKeyContent := map[string]int{} |
|
|
|
for _, sshKey := range responseObject.SSHKeys { |
|
digitalOceanIdByKeyContent[strings.TrimSpace(sshKey.PublicKey)] = sshKey.Id |
|
} |
|
|
|
importedAnySSHKeys := false |
|
|
|
// for each local SSH key which tf plans to create, check if it already exists in DO |
|
for _, resource := range createSSHKeys { |
|
sshKeyContent, hasContent := getStringValue(resource, "public_key") |
|
if !hasContent { |
|
return false, fmt.Errorf("digitalocean_ssh_key %s (from terraform planned_values) is missing string value \"public_key\" ", resource.Address) |
|
} |
|
digitalOceanId, has := digitalOceanIdByKeyContent[strings.TrimSpace(sshKeyContent)] |
|
if has { |
|
fmt.Println("---------------------------------------") |
|
fmt.Printf( |
|
"Terraform plans to add the local ssh public key %s to digitalocean, but digitalocean already has that key \n", |
|
resource.Values["name"], |
|
) |
|
exitCode := removeAndImportResource(terraformDirectory, resource.Address, strconv.Itoa(digitalOceanId)) |
|
|
|
if exitCode != 0 { |
|
return false, errors.New("terraform import returned a non-zero exit code") |
|
} |
|
importedAnySSHKeys = true |
|
|
|
fmt.Println("---------------------------------------") |
|
} |
|
|
|
} |
|
|
|
return importedAnySSHKeys, nil |
|
}
|
|
|