1package tfe
2
3import (
4	"context"
5	"errors"
6	"fmt"
7	"net/url"
8	"time"
9)
10
11// Compile-time proof of interface implementation.
12var _ AgentTokens = (*agentTokens)(nil)
13
14// AgentTokens describes all the agent token related methods that the
15// Terraform Cloud API supports.
16//
17// TFE API docs:
18// https://www.terraform.io/docs/cloud/api/agent-tokens.html
19type AgentTokens interface {
20	// List all the agent tokens of the given agent pool.
21	List(ctx context.Context, agentPoolID string) (*AgentTokenList, error)
22
23	// Generate a new agent token with the given options.
24	Generate(ctx context.Context, agentPoolID string, options AgentTokenGenerateOptions) (*AgentToken, error)
25
26	// Read an agent token by its ID.
27	Read(ctx context.Context, agentTokenID string) (*AgentToken, error)
28
29	// Delete an agent token by its ID.
30	Delete(ctx context.Context, agentTokenID string) error
31}
32
33// agentTokens implements AgentTokens.
34type agentTokens struct {
35	client *Client
36}
37
38// AgentTokenList represents a list of agent tokens.
39type AgentTokenList struct {
40	*Pagination
41	Items []*AgentToken
42}
43
44// AgentToken represents a Terraform Cloud agent token.
45type AgentToken struct {
46	ID          string    `jsonapi:"primary,authentication-tokens"`
47	CreatedAt   time.Time `jsonapi:"attr,created-at,iso8601"`
48	Description string    `jsonapi:"attr,description"`
49	LastUsedAt  time.Time `jsonapi:"attr,last-used-at,iso8601"`
50	Token       string    `jsonapi:"attr,token"`
51}
52
53// List all the agent tokens of the given agent pool.
54func (s *agentTokens) List(ctx context.Context, agentPoolID string) (*AgentTokenList, error) {
55	if !validStringID(&agentPoolID) {
56		return nil, errors.New("invalid value for agent pool ID")
57	}
58
59	u := fmt.Sprintf("agent-pools/%s/authentication-tokens", url.QueryEscape(agentPoolID))
60	req, err := s.client.newRequest("GET", u, nil)
61	if err != nil {
62		return nil, err
63	}
64
65	tokenList := &AgentTokenList{}
66	err = s.client.do(ctx, req, tokenList)
67	if err != nil {
68		return nil, err
69	}
70
71	return tokenList, nil
72}
73
74// AgentTokenGenerateOptions represents the options for creating an agent token.
75type AgentTokenGenerateOptions struct {
76	// For internal use only!
77	ID string `jsonapi:"primary,agent-tokens"`
78
79	// Description of the token
80	Description *string `jsonapi:"attr,description"`
81}
82
83// Generate a new agent token with the given options.
84func (s *agentTokens) Generate(ctx context.Context, agentPoolID string, options AgentTokenGenerateOptions) (*AgentToken, error) {
85	if !validStringID(&agentPoolID) {
86		return nil, errors.New("invalid value for agent pool ID")
87	}
88
89	if !validString(options.Description) {
90		return nil, errors.New("agent token description can't be blank")
91	}
92
93	// Make sure we don't send a user provided ID.
94	options.ID = ""
95
96	u := fmt.Sprintf("agent-pools/%s/authentication-tokens", url.QueryEscape(agentPoolID))
97	req, err := s.client.newRequest("POST", u, &options)
98	if err != nil {
99		return nil, err
100	}
101
102	at := &AgentToken{}
103	err = s.client.do(ctx, req, at)
104	if err != nil {
105		return nil, err
106	}
107
108	return at, err
109}
110
111// Read an agent token by its ID.
112func (s *agentTokens) Read(ctx context.Context, agentTokenID string) (*AgentToken, error) {
113	if !validStringID(&agentTokenID) {
114		return nil, errors.New("invalid value for agent token ID")
115	}
116
117	u := fmt.Sprintf("authentication-tokens/%s", url.QueryEscape(agentTokenID))
118	req, err := s.client.newRequest("GET", u, nil)
119	if err != nil {
120		return nil, err
121	}
122
123	at := &AgentToken{}
124	err = s.client.do(ctx, req, at)
125	if err != nil {
126		return nil, err
127	}
128
129	return at, err
130}
131
132// Delete an agent token by its ID.
133func (s *agentTokens) Delete(ctx context.Context, agentTokenID string) error {
134	if !validStringID(&agentTokenID) {
135		return errors.New("invalid value for agent token ID")
136	}
137
138	u := fmt.Sprintf("authentication-tokens/%s", url.QueryEscape(agentTokenID))
139	req, err := s.client.newRequest("DELETE", u, nil)
140	if err != nil {
141		return err
142	}
143
144	return s.client.do(ctx, req, nil)
145}
146