Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add agent data source #456

Merged
merged 23 commits into from Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
cd5c837
Add new agent data source to client
laurenolivia Jul 27, 2022
30d48a6
merge conflicts
laurenolivia Jul 27, 2022
40387c3
resolve errors.go
laurenolivia Jul 27, 2022
b2451da
Merge remote-tracking branch 'origin' into laurenolivia/add-agent-dat…
laurenolivia Aug 3, 2022
2bc473b
merge conflicts, re-add createAgent fn
laurenolivia Aug 3, 2022
c9cd163
cleaning up log statements, shorten helper fn sig
laurenolivia Aug 3, 2022
17618f1
remove options from interface
laurenolivia Aug 4, 2022
ce05456
refactor
laurenolivia Aug 5, 2022
7d6ecc7
Merge remote-tracking branch 'origin' into laurenolivia/add-agent-dat…
laurenolivia Aug 5, 2022
b9674cc
small fixes
laurenolivia Aug 5, 2022
055069d
refactor helper fn, integration tests
laurenolivia Aug 9, 2022
587fdf0
Merge remote-tracking branch 'origin' into laurenolivia/add-agent-dat…
laurenolivia Aug 10, 2022
5bd3c24
replace docker with biniary
laurenolivia Aug 10, 2022
53518dc
add
laurenolivia Aug 10, 2022
94bc1e4
create agent pool within create agent fn, return pool
laurenolivia Aug 10, 2022
c16d315
add mocks
laurenolivia Aug 10, 2022
f1cc0db
create skipIfNotRuntime fn
laurenolivia Aug 10, 2022
f81e98b
remove extra line
laurenolivia Aug 10, 2022
9a7d547
move upgradeOrg down one line
laurenolivia Aug 11, 2022
d6a6734
rename skipIf fn
laurenolivia Aug 11, 2022
b98f0f0
Merge remote-tracking branch 'origin' into laurenolivia/add-agent-dat…
laurenolivia Aug 11, 2022
1021667
remove a var not in main
laurenolivia Aug 11, 2022
a493b3d
rename to LastPingSince
laurenolivia Aug 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -63,6 +63,7 @@ For complete usage of the API client, see the [full package docs](https://pkg.go
This API client covers most of the existing Terraform Cloud API calls and is updated regularly to add new or missing endpoints.

- [x] Account
- [x] Agents
- [x] Agent Pools
- [x] Agent Tokens
- [x] Applies
Expand Down
90 changes: 90 additions & 0 deletions agent.go
@@ -0,0 +1,90 @@
package tfe

import (
"context"
"fmt"
"net/url"
)

// Compile-time proof of interface implementation.
var _ Agents = (*agents)(nil)

// Agents describes all the agent-related methods that the
// Terraform Cloud API supports.
// TFE API docs: https://www.terraform.io/docs/cloud/api/agents.html
type Agents interface {
// Read an agent by its ID.
Read(ctx context.Context, agentID string) (*Agent, error)

// List all the agents of the given pool.
List(ctx context.Context, agentPoolID string, options *AgentListOptions) (*AgentList, error)
}

// agents implements Agents.
type agents struct {
client *Client
}

// AgentList represents a list of agents.
type AgentList struct {
*Pagination
Items []*Agent
}

// Agent represents a Terraform Cloud agent.
type Agent struct {
ID string `jsonapi:"primary,agents"`
Name string `jsonapi:"attr,name"`
IP string `jsonapi:"attr,ip-address"`
Status string `jsonapi:"attr,status"`
LastPingAt string `jsonapi:"attr,last-ping-at"`
}

type AgentListOptions struct {
ListOptions
laurenolivia marked this conversation as resolved.
Show resolved Hide resolved

//Optional:
Filter string `url:"filter[last-ping-since],omitempty"`
laurenolivia marked this conversation as resolved.
Show resolved Hide resolved
}

// Read a single agent by its ID
func (s *agents) Read(ctx context.Context, agentID string) (*Agent, error) {
if !validStringID(&agentID) {
return nil, ErrInvalidAgentID
}

u := fmt.Sprintf("agents/%s", url.QueryEscape(agentID))
req, err := s.client.NewRequest("GET", u, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should pass options here instead of nil.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly another sign that this method isn't needed! 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sebasslash 👍
@nfagerlund Can you elaborate on why it's a sign that the method, possibly, isn't needed❔

if err != nil {
return nil, err
}

agent := &Agent{}
err = req.Do(ctx, agent)
if err != nil {
return nil, err
}

return agent, nil
}

// List all the agents of the given organization.
func (s *agents) List(ctx context.Context, agentPoolID string, options *AgentListOptions) (*AgentList, error) {
if !validStringID(&agentPoolID) {
return nil, ErrInvalidOrg
}

u := fmt.Sprintf("agent-pools/%s/agents", url.QueryEscape(agentPoolID))
req, err := s.client.NewRequest("GET", u, options)
if err != nil {
return nil, err
}

agentList := &AgentList{}
err = req.Do(ctx, agentList)
if err != nil {
return nil, err
}

return agentList, nil
}
75 changes: 75 additions & 0 deletions agent_integration_test.go
@@ -0,0 +1,75 @@
//go:build integration
// +build integration

package tfe

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestAgentsRead(t *testing.T) {
skipIfNotLinuxAmd64(t)

client := testClient(t)
ctx := context.Background()

org, orgCleanup := createOrganization(t, client)
t.Cleanup(orgCleanup)

upgradeOrganizationSubscription(t, client, org)

agent, _, agentCleanup := createAgent(t, client, org)

t.Cleanup(agentCleanup)

t.Run("when the agent exists", func(t *testing.T) {
k, err := client.Agents.Read(ctx, agent.ID)
require.NoError(t, err)
assert.Equal(t, agent, k)
})

t.Run("when the agent does not exist", func(t *testing.T) {
k, err := client.Agents.Read(ctx, "nonexistent")
assert.Nil(t, k)
assert.Equal(t, err, ErrResourceNotFound)
})

t.Run("without a valid agent ID", func(t *testing.T) {
k, err := client.Agents.Read(ctx, badIdentifier)
assert.Nil(t, k)
assert.EqualError(t, err, ErrInvalidAgentID.Error())
})
}

func TestAgentsList(t *testing.T) {
skipIfNotLinuxAmd64(t)

client := testClient(t)
ctx := context.Background()

org, orgCleanup := createOrganization(t, client)
t.Cleanup(orgCleanup)

upgradeOrganizationSubscription(t, client, org)

_, agentPool, agentCleanup := createAgent(t, client, org)
t.Cleanup(agentCleanup)

t.Run("expect an agent to exist", func(t *testing.T) {
agent, err := client.Agents.List(ctx, agentPool.ID, nil)

require.NoError(t, err)
require.NotEmpty(t, agent.Items)
assert.NotEmpty(t, agent.Items[0].ID)
})

t.Run("without a valid agent pool ID", func(t *testing.T) {
agent, err := client.Agents.List(ctx, badIdentifier, nil)
assert.Nil(t, agent)
assert.EqualError(t, err, ErrInvalidOrg.Error())
})
}
4 changes: 2 additions & 2 deletions agent_pool.go
Expand Up @@ -20,10 +20,10 @@ type AgentPools interface {
// Create a new agent pool with the given options.
Create(ctx context.Context, organization string, options AgentPoolCreateOptions) (*AgentPool, error)

// Read a agent pool by its ID.
// Read an agent pool by its ID.
Read(ctx context.Context, agentPoolID string) (*AgentPool, error)

// Read a agent pool by its ID with the given options.
// Read an agent pool by its ID with the given options.
ReadWithOptions(ctx context.Context, agentPoolID string, options *AgentPoolReadOptions) (*AgentPool, error)

// Update an agent pool by its ID.
Expand Down
2 changes: 2 additions & 0 deletions errors.go
Expand Up @@ -176,6 +176,8 @@ var (

ErrInvalidArch = errors.New("invalid value for arch")

ErrInvalidAgentID = errors.New("invalid value for Agent ID")

ErrInvalidRegistryName = errors.New(`invalid value for registry-name. It must be either "private" or "public"`)
)

Expand Down
1 change: 1 addition & 0 deletions generate_mocks.sh
Expand Up @@ -60,3 +60,4 @@ mockgen -source=variable_set.go -destination=mocks/variable_set_mocks.go -packag
mockgen -source=variable_set_variable.go -destination=mocks/variable_set_variable_mocks.go -package=mocks
mockgen -source=workspace.go -destination=mocks/workspace_mocks.go -package=mocks
mockgen -source=workspace_run_task.go -destination=mocks/workspace_run_tasks_mocks.go -package=mocks
mockgen -source=agent.go -destination=mocks/agents.go -package=mocks