api: starting intention endpoints, reorganize files slightly
This commit is contained in:
parent
b5b301aa2a
commit
9c33068394
|
@ -1,37 +1,5 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// CARootList is the structure for the results of listing roots.
|
||||
type CARootList struct {
|
||||
ActiveRootID string
|
||||
Roots []*CARoot
|
||||
}
|
||||
|
||||
// CARoot is a single CA within Connect.
|
||||
type CARoot struct {
|
||||
ID string
|
||||
Name string
|
||||
RootCert string
|
||||
Active bool
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
type IssuedCert struct {
|
||||
SerialNumber string
|
||||
CertPEM string
|
||||
PrivateKeyPEM string
|
||||
Service string
|
||||
ServiceURI string
|
||||
ValidAfter time.Time
|
||||
ValidBefore time.Time
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// Connect can be used to work with endpoints related to Connect, the
|
||||
// feature for securely connecting services within Consul.
|
||||
type Connect struct {
|
||||
|
@ -42,24 +10,3 @@ type Connect struct {
|
|||
func (c *Client) Connect() *Connect {
|
||||
return &Connect{c}
|
||||
}
|
||||
|
||||
// CARoots queries the list of available roots.
|
||||
func (h *Connect) CARoots(q *QueryOptions) (*CARootList, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/ca/roots")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out CARootList
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &out, qm, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// CARootList is the structure for the results of listing roots.
|
||||
type CARootList struct {
|
||||
ActiveRootID string
|
||||
Roots []*CARoot
|
||||
}
|
||||
|
||||
// CARoot represents a root CA certificate that is trusted.
|
||||
type CARoot struct {
|
||||
// ID is a globally unique ID (UUID) representing this CA root.
|
||||
ID string
|
||||
|
||||
// Name is a human-friendly name for this CA root. This value is
|
||||
// opaque to Consul and is not used for anything internally.
|
||||
Name string
|
||||
|
||||
// RootCert is the PEM-encoded public certificate.
|
||||
RootCert string
|
||||
|
||||
// Active is true if this is the current active CA. This must only
|
||||
// be true for exactly one CA. For any method that modifies roots in the
|
||||
// state store, tests should be written to verify that multiple roots
|
||||
// cannot be active.
|
||||
Active bool
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// IssuedCert is a certificate that has been issued by a Connect CA.
|
||||
type IssuedCert struct {
|
||||
// SerialNumber is the unique serial number for this certificate.
|
||||
// This is encoded in standard hex separated by :.
|
||||
SerialNumber string
|
||||
|
||||
// CertPEM and PrivateKeyPEM are the PEM-encoded certificate and private
|
||||
// key for that cert, respectively. This should not be stored in the
|
||||
// state store, but is present in the sign API response.
|
||||
CertPEM string `json:",omitempty"`
|
||||
PrivateKeyPEM string `json:",omitempty"`
|
||||
|
||||
// Service is the name of the service for which the cert was issued.
|
||||
// ServiceURI is the cert URI value.
|
||||
Service string
|
||||
ServiceURI string
|
||||
|
||||
// ValidAfter and ValidBefore are the validity periods for the
|
||||
// certificate.
|
||||
ValidAfter time.Time
|
||||
ValidBefore time.Time
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// CARoots queries the list of available roots.
|
||||
func (h *Connect) CARoots(q *QueryOptions) (*CARootList, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/ca/roots")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out CARootList
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &out, qm, nil
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Intention defines an intention for the Connect Service Graph. This defines
|
||||
// the allowed or denied behavior of a connection between two services using
|
||||
// Connect.
|
||||
type Intention struct {
|
||||
// ID is the UUID-based ID for the intention, always generated by Consul.
|
||||
ID string
|
||||
|
||||
// Description is a human-friendly description of this intention.
|
||||
// It is opaque to Consul and is only stored and transferred in API
|
||||
// requests.
|
||||
Description string
|
||||
|
||||
// SourceNS, SourceName are the namespace and name, respectively, of
|
||||
// the source service. Either of these may be the wildcard "*", but only
|
||||
// the full value can be a wildcard. Partial wildcards are not allowed.
|
||||
// The source may also be a non-Consul service, as specified by SourceType.
|
||||
//
|
||||
// DestinationNS, DestinationName is the same, but for the destination
|
||||
// service. The same rules apply. The destination is always a Consul
|
||||
// service.
|
||||
SourceNS, SourceName string
|
||||
DestinationNS, DestinationName string
|
||||
|
||||
// SourceType is the type of the value for the source.
|
||||
SourceType IntentionSourceType
|
||||
|
||||
// Action is whether this is a whitelist or blacklist intention.
|
||||
Action IntentionAction
|
||||
|
||||
// DefaultAddr, DefaultPort of the local listening proxy (if any) to
|
||||
// make this connection.
|
||||
DefaultAddr string
|
||||
DefaultPort int
|
||||
|
||||
// Meta is arbitrary metadata associated with the intention. This is
|
||||
// opaque to Consul but is served in API responses.
|
||||
Meta map[string]string
|
||||
|
||||
// CreatedAt and UpdatedAt keep track of when this record was created
|
||||
// or modified.
|
||||
CreatedAt, UpdatedAt time.Time
|
||||
|
||||
CreateIndex uint64
|
||||
ModifyIndex uint64
|
||||
}
|
||||
|
||||
// IntentionAction is the action that the intention represents. This
|
||||
// can be "allow" or "deny" to whitelist or blacklist intentions.
|
||||
type IntentionAction string
|
||||
|
||||
const (
|
||||
IntentionActionAllow IntentionAction = "allow"
|
||||
IntentionActionDeny IntentionAction = "deny"
|
||||
)
|
||||
|
||||
// IntentionSourceType is the type of the source within an intention.
|
||||
type IntentionSourceType string
|
||||
|
||||
const (
|
||||
// IntentionSourceConsul is a service within the Consul catalog.
|
||||
IntentionSourceConsul IntentionSourceType = "consul"
|
||||
)
|
||||
|
||||
// Intentions returns the list of intentions.
|
||||
func (h *Connect) Intentions(q *QueryOptions) ([]*Intention, *QueryMeta, error) {
|
||||
r := h.c.newRequest("GET", "/v1/connect/intentions")
|
||||
r.setQueryOptions(q)
|
||||
rtt, resp, err := requireOK(h.c.doRequest(r))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
qm := &QueryMeta{}
|
||||
parseQueryMeta(resp, qm)
|
||||
qm.RequestTime = rtt
|
||||
|
||||
var out []*Intention
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return out, qm, nil
|
||||
}
|
||||
|
||||
// IntentionCreate will create a new intention. The ID in the given
|
||||
// structure must be empty and a generate ID will be returned on
|
||||
// success.
|
||||
func (c *Connect) IntentionCreate(ixn *Intention, q *WriteOptions) (string, *WriteMeta, error) {
|
||||
r := c.c.newRequest("POST", "/v1/connect/intentions")
|
||||
r.setWriteOptions(q)
|
||||
r.obj = ixn
|
||||
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wm := &WriteMeta{}
|
||||
wm.RequestTime = rtt
|
||||
|
||||
var out struct{ ID string }
|
||||
if err := decodeBody(resp, &out); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return out.ID, wm, nil
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAPI_ConnectIntentionCreate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
require := require.New(t)
|
||||
c, s := makeClient(t)
|
||||
defer s.Stop()
|
||||
|
||||
connect := c.Connect()
|
||||
|
||||
// Create
|
||||
ixn := testIntention()
|
||||
id, _, err := connect.IntentionCreate(ixn, nil)
|
||||
require.Nil(err)
|
||||
require.NotEmpty(id)
|
||||
|
||||
// List it
|
||||
list, _, err := connect.Intentions(nil)
|
||||
require.Nil(err)
|
||||
require.Len(list, 1)
|
||||
|
||||
actual := list[0]
|
||||
ixn.ID = id
|
||||
ixn.CreatedAt = actual.CreatedAt
|
||||
ixn.UpdatedAt = actual.UpdatedAt
|
||||
ixn.CreateIndex = actual.CreateIndex
|
||||
ixn.ModifyIndex = actual.ModifyIndex
|
||||
require.Equal(ixn, actual)
|
||||
}
|
||||
|
||||
func testIntention() *Intention {
|
||||
return &Intention{
|
||||
SourceNS: "eng",
|
||||
SourceName: "api",
|
||||
DestinationNS: "eng",
|
||||
DestinationName: "db",
|
||||
Action: IntentionActionAllow,
|
||||
SourceType: IntentionSourceConsul,
|
||||
Meta: map[string]string{},
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue