Skip to content

Commit

Permalink
Merge pull request #113 from rundeck/0.4.7
Browse files Browse the repository at this point in the history
0.4.7 Release PR
  • Loading branch information
fdevans committed Oct 30, 2023
2 parents df2ac9e + 25af7ca commit f178341
Show file tree
Hide file tree
Showing 18 changed files with 717 additions and 165 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ website/node_modules
*.iml
*.test
*.iml
terraform-provider-rundeck

website/vendor

Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.4.7
- Added Password Resource
- Added Orchestrator option to Job Definition
- Added Hidden flag for Job Options

## 0.4.6
- Added Retry Delay setting to Job definition.
- Added ability to set Secure Options in Job Definition.
Expand Down
Empty file added props/tokens.properties
Empty file.
29 changes: 22 additions & 7 deletions rundeck/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type JobDetail struct {
Timeout string `xml:"timeout,omitempty"`
Retry *Retry `xml:"retry,omitempty"`
NodeFilter *JobNodeFilter `xml:"nodefilters,omitempty"`
Orchestrator *JobOrchestrator `xml:"orchestrator,omitempty"`

/* If Dispatch is enabled, nodesSelectedByDefault is always present with true/false.
* by this reason omitempty cannot be present.
Expand Down Expand Up @@ -207,6 +208,9 @@ type JobOption struct {

// Description of the value to be shown in the Rundeck UI.
Description string `xml:"description,omitempty"`

// Option should be hidden from job run page
Hidden bool `xml:"hidden,omitempty"`
}

// JobValueChoices is a specialization of []string representing a sequence of predefined values
Expand Down Expand Up @@ -317,6 +321,20 @@ type JobNodeFilter struct {
ExcludePrecedence bool `xml:"excludeprecedence,omitempty"`
}

// JobOrchestratorConfig Contains the options for the Job Orchestrators
type JobOrchestratorConfig struct {
Count int `xml:"count,omitempty"`
Percent int `xml:"percent,omitempty"`
Attribute string `xml:"attribute,omitempty"`
Sort string `xml:"sort,omitempty"`
}

// JobOrchestrator describes how to schedule the jobs, in what order, and on how many nodes
type JobOrchestrator struct {
Config JobOrchestratorConfig `xml:"configuration"`
Type string `xml:"type"`
}

type jobImportResults struct {
Succeeded jobImportResultsCategory `xml:"succeeded"`
Failed jobImportResultsCategory `xml:"failed"`
Expand Down Expand Up @@ -511,14 +529,11 @@ func (c *JobValueChoices) UnmarshalXMLAttr(attr xml.Attr) error {

func (a JobCommandJobRefArguments) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Attr = []xml.Attr{
{Name: xml.Name{Local: "line"}, Value: string(a)},
xml.Attr{Name: xml.Name{Local: "line"}, Value: string(a)},
}
err := e.EncodeToken(start)
if err != nil {
return err
}
err = e.EncodeToken(xml.EndElement{Name: start.Name})
return err
e.EncodeToken(start)
e.EncodeToken(xml.EndElement{Name: start.Name})
return nil
}

func (a *JobCommandJobRefArguments) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
Expand Down
1 change: 1 addition & 0 deletions rundeck/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func Provider() terraform.ResourceProvider {
"rundeck_project": resourceRundeckProject(),
"rundeck_job": resourceRundeckJob(),
"rundeck_private_key": resourceRundeckPrivateKey(),
"rundeck_password": resourceRundeckPassword(),
"rundeck_public_key": resourceRundeckPublicKey(),
"rundeck_acl_policy": resourceRundeckAclPolicy(),
},
Expand Down
138 changes: 138 additions & 0 deletions rundeck/resource_base_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package rundeck

import (
"context"
"crypto/sha1"
"encoding/hex"
"fmt"
"io"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"

"github.com/rundeck/go-rundeck/rundeck"
)

type BaseKeyType int32

const (
PRIVATE_KEY BaseKeyType = 0
PASSWORD BaseKeyType = 1
)

func CreateOrUpdateBaseKey(d *schema.ResourceData, meta interface{}, baseKeyType BaseKeyType) error {
client := meta.(*rundeck.BaseClient)

var payload string
path := d.Get("path").(string)

var err error

ctx := context.Background()

var contentType string
switch baseKeyType {
case PRIVATE_KEY:
contentType = "application/octet-stream"
payload = d.Get("key_material").(string)
case PASSWORD:
contentType = "application/x-rundeck-data-password"
payload = d.Get("password").(string)
default:
return fmt.Errorf("Internal error. Unknown key type")
}

payloadReader := io.NopCloser(strings.NewReader(payload))

if d.Id() != "" {
resp, err := client.StorageKeyUpdate(ctx, path, payloadReader, contentType)
if resp.StatusCode == 409 || err != nil {
return fmt.Errorf("Error updating or adding key: Key exists")
}
} else {
resp, err := client.StorageKeyCreate(ctx, path, payloadReader, contentType)
if resp.StatusCode == 409 || err != nil {
return fmt.Errorf("Error updating or adding key: Key exists")
}
}

if err != nil {
return err
}

d.SetId(path)

return ReadBaseKey(d, meta)
}

func DeleteBaseKey(d *schema.ResourceData, meta interface{}) error {
client := meta.(*rundeck.BaseClient)
ctx := context.Background()

path := d.Id()

// The only "delete" call we have is oblivious to key type, but
// that's okay since our Exists implementation makes sure that we
// won't try to delete a key of the wrong type since we'll pretend
// that it's already been deleted.
_, err := client.StorageKeyDelete(ctx, path)
if err != nil {
return err
}

d.SetId("")
return nil
}

func ReadBaseKey(d *schema.ResourceData, meta interface{}) error {
// Nothing to read for a private key: existence is all we need to
// worry about, and PrivateKeyExists took care of that.
return nil
}

func BaseKeyExists(d *schema.ResourceData, meta interface{}, baseKeyType BaseKeyType) (bool, error) {
client := meta.(*rundeck.BaseClient)
ctx := context.Background()

path := d.Id()

resp, err := client.StorageKeyGetMetadata(ctx, path)
if err != nil {
if resp.StatusCode != 404 {
err = nil
}
return false, err
}

// If the resource is not password or private key as far as this resource is
// concerned it doesn't exist. (We'll fail properly when we try to
// create a key where one already exists.)
// Content-type are:
// application/octet-stream specifies a private key
// application/pgp-keys specifies a public key
// application/x-rundeck-data-password specifies a password
switch baseKeyType {
case PRIVATE_KEY:
if *resp.Meta.RundeckContentType != "application/octet-stream" {
return false, nil
}
case PASSWORD:
if *resp.Meta.RundeckContentType != "application/x-rundeck-data-password" {
return false, nil
}
default:
return false, fmt.Errorf("Internal error. Unknown key type")
}

return true, nil
}

func BaseKeyStateFunction(val interface{}) string {
switch v := val.(type) {
case string:
hash := sha1.Sum([]byte(v))
return hex.EncodeToString(hash[:])
default:
return ""
}
}
53 changes: 53 additions & 0 deletions rundeck/resource_base_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package rundeck

import (
"context"
"fmt"

"github.com/rundeck/go-rundeck/rundeck"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func testAccBaseKeyCheckDestroy(key *rundeck.StorageKeyListResponse) resource.TestCheckFunc {
return func(s *terraform.State) error {
client := testAccProvider.Meta().(*rundeck.BaseClient)
ctx := context.Background()

resp, err := client.StorageKeyGetMetadata(ctx, *key.Path)

if resp.StatusCode == 200 {
return fmt.Errorf("key still exists")
}
if resp.StatusCode != 404 {
return fmt.Errorf("got something other than NotFoundError (%v) when getting key", err)
}

return nil
}
}

func testAccBaseKeyCheckExists(rn string, key *rundeck.StorageKeyListResponse) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[rn]
if !ok {
return fmt.Errorf("resource not found: %s", rn)
}

if rs.Primary.ID == "" {
return fmt.Errorf("key id not set")
}

client := testAccProvider.Meta().(*rundeck.BaseClient)
ctx := context.Background()
gotKey, err := client.StorageKeyGetMetadata(ctx, rs.Primary.ID)
if gotKey.StatusCode == 404 || err != nil {
return fmt.Errorf("error getting key metadata: %s", err)
}

*key = gotKey

return nil
}
}
Loading

0 comments on commit f178341

Please sign in to comment.