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

Adds Elasticsearch logging endpoint support #90

Merged
merged 1 commit into from
May 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pkg/api/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ type Interface interface {
UpdateDigitalOcean(*fastly.UpdateDigitalOceanInput) (*fastly.DigitalOcean, error)
DeleteDigitalOcean(*fastly.DeleteDigitalOceanInput) error

CreateElasticsearch(*fastly.CreateElasticsearchInput) (*fastly.Elasticsearch, error)
ListElasticsearch(*fastly.ListElasticsearchInput) ([]*fastly.Elasticsearch, error)
GetElasticsearch(*fastly.GetElasticsearchInput) (*fastly.Elasticsearch, error)
UpdateElasticsearch(*fastly.UpdateElasticsearchInput) (*fastly.Elasticsearch, error)
DeleteElasticsearch(*fastly.DeleteElasticsearchInput) error

GetUser(*fastly.GetUserInput) (*fastly.User, error)

GetRegions() (*fastly.RegionsResponse, error)
Expand Down
15 changes: 15 additions & 0 deletions pkg/app/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/fastly/cli/pkg/logging/bigquery"
"github.com/fastly/cli/pkg/logging/cloudfiles"
"github.com/fastly/cli/pkg/logging/digitalocean"
"github.com/fastly/cli/pkg/logging/elasticsearch"
"github.com/fastly/cli/pkg/logging/ftp"
"github.com/fastly/cli/pkg/logging/gcs"
"github.com/fastly/cli/pkg/logging/heroku"
Expand Down Expand Up @@ -260,6 +261,13 @@ func Run(args []string, env config.Environment, file config.File, configFilePath
statsHistorical := stats.NewHistoricalCommand(statsRoot.CmdClause, &globals)
statsRealtime := stats.NewRealtimeCommand(statsRoot.CmdClause, &globals)

elasticsearchRoot := elasticsearch.NewRootCommand(loggingRoot.CmdClause, &globals)
elasticsearchCreate := elasticsearch.NewCreateCommand(elasticsearchRoot.CmdClause, &globals)
elasticsearchList := elasticsearch.NewListCommand(elasticsearchRoot.CmdClause, &globals)
elasticsearchDescribe := elasticsearch.NewDescribeCommand(elasticsearchRoot.CmdClause, &globals)
elasticsearchUpdate := elasticsearch.NewUpdateCommand(elasticsearchRoot.CmdClause, &globals)
elasticsearchDelete := elasticsearch.NewDeleteCommand(elasticsearchRoot.CmdClause, &globals)

commands := []common.Command{
configureRoot,
whoamiRoot,
Expand Down Expand Up @@ -430,6 +438,13 @@ func Run(args []string, env config.Environment, file config.File, configFilePath
digitaloceanUpdate,
digitaloceanDelete,

elasticsearchRoot,
elasticsearchCreate,
elasticsearchList,
elasticsearchDescribe,
elasticsearchUpdate,
elasticsearchDelete,

statsRoot,
statsRegions,
statsHistorical,
Expand Down
135 changes: 135 additions & 0 deletions pkg/app/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2015,6 +2015,141 @@ COMMANDS
-n, --name=NAME The name of the DigitalOcean Spaces logging
object

logging elasticsearch create --name=NAME --version=VERSION --index=INDEX --url=URL [<flags>]
Create an Elasticsearch logging endpoint on a Fastly service version

-n, --name=NAME The name of the Elasticsearch logging object.
Used as a primary key for API access
-s, --service-id=SERVICE-ID Service ID
--version=VERSION Number of service version
--index=INDEX The name of the Elasticsearch index to send
documents (logs) to. The index must follow
the Elasticsearch index format rules
(https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html).
We support strftime
(http://man7.org/linux/man-pages/man3/strftime.3.html)
interpolated variables inside braces prefixed
with a pound symbol. For example, #{%F} will
interpolate as YYYY-MM-DD with today's date
--url=URL The URL to stream logs to. Must use HTTPS.
--pipeline=PIPELINE The ID of the Elasticsearch ingest pipeline
to apply pre-process transformations to
before indexing. For example my_pipeline_id.
Learn more about creating a pipeline in the
Elasticsearch docs
(https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest.html)
--tls-ca-cert=TLS-CA-CERT A secure certificate to authenticate the
server with. Must be in PEM format
--tls-client-cert=TLS-CLIENT-CERT
The client certificate used to make
authenticated requests. Must be in PEM format
--tls-client-key=TLS-CLIENT-KEY
The client private key used to make
authenticated requests. Must be in PEM format
--tls-hostname=TLS-HOSTNAME
The hostname used to verify the server's
certificate. It can either be the Common Name
or a Subject Alternative Name (SAN)
--format=FORMAT Apache style log formatting. Your log must
produce valid JSON that Elasticsearch can
ingest
--format-version=FORMAT-VERSION
The version of the custom logging format used
for the configured endpoint. Can be either 2
(default) or 1
--placement=PLACEMENT Where in the generated VCL the logging call
should be placed, overriding any
format_version default. Can be none or
waf_debug
--response-condition=RESPONSE-CONDITION
The name of an existing condition in the
configured endpoint, or leave blank to always
execute
--request-max-entries=REQUEST-MAX-ENTRIES
Maximum number of logs to append to a batch,
if non-zero. Defaults to 0 for unbounded
--request-max-bytes=REQUEST-MAX-BYTES
Maximum size of log batch, if non-zero.
Defaults to 0 for unbounded

logging elasticsearch list --version=VERSION [<flags>]
List Elasticsearch endpoints on a Fastly service version

-s, --service-id=SERVICE-ID Service ID
--version=VERSION Number of service version

logging elasticsearch describe --version=VERSION --name=NAME [<flags>]
Show detailed information about an Elasticsearch logging endpoint on a
Fastly service version

-s, --service-id=SERVICE-ID Service ID
--version=VERSION Number of service version
-n, --name=NAME The name of the Elasticsearch logging object

logging elasticsearch update --version=VERSION --name=NAME [<flags>]
Update an Elasticsearch logging endpoint on a Fastly service version

-s, --service-id=SERVICE-ID Service ID
--version=VERSION Number of service version
-n, --name=NAME The name of the Elasticsearch logging object
--new-name=NEW-NAME New name of the Elasticsearch logging object
--index=INDEX The name of the Elasticsearch index to send
documents (logs) to. The index must follow
the Elasticsearch index format rules
(https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html).
We support strftime
(http://man7.org/linux/man-pages/man3/strftime.3.html)
interpolated variables inside braces prefixed
with a pound symbol. For example, #{%F} will
interpolate as YYYY-MM-DD with today's date
--url=URL The URL to stream logs to. Must use HTTPS.
--pipeline=PIPELINE The ID of the Elasticsearch ingest pipeline
to apply pre-process transformations to
before indexing. For example my_pipeline_id.
Learn more about creating a pipeline in the
Elasticsearch docs
(https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest.html)
--tls-ca-cert=TLS-CA-CERT A secure certificate to authenticate the
server with. Must be in PEM format
--tls-client-cert=TLS-CLIENT-CERT
The client certificate used to make
authenticated requests. Must be in PEM format
--tls-client-key=TLS-CLIENT-KEY
The client private key used to make
authenticated requests. Must be in PEM format
--tls-hostname=TLS-HOSTNAME
The hostname used to verify the server's
certificate. It can either be the Common Name
or a Subject Alternative Name (SAN)
--format=FORMAT Apache style log formatting. Your log must
produce valid JSON that Elasticsearch can
ingest
--format-version=FORMAT-VERSION
The version of the custom logging format used
for the configured endpoint. Can be either 2
(default) or 1
--placement=PLACEMENT Where in the generated VCL the logging call
should be placed, overriding any
format_version default. Can be none or
waf_debug
--response-condition=RESPONSE-CONDITION
The name of an existing condition in the
configured endpoint, or leave blank to always
execute
--request-max-entries=REQUEST-MAX-ENTRIES
Maximum number of logs to append to a batch,
if non-zero. Defaults to 0 for unbounded
--request-max-bytes=REQUEST-MAX-BYTES
Maximum size of log batch, if non-zero.
Defaults to 0 for unbounded

logging elasticsearch delete --version=VERSION --name=NAME [<flags>]
Delete an Elasticsearch logging endpoint on a Fastly service version

-s, --service-id=SERVICE-ID Service ID
--version=VERSION Number of service version
-n, --name=NAME The name of the Elasticsearch logging object

stats regions
List stats regions

Expand Down
154 changes: 154 additions & 0 deletions pkg/logging/elasticsearch/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package elasticsearch

import (
"io"

"github.com/fastly/cli/pkg/common"
"github.com/fastly/cli/pkg/compute/manifest"
"github.com/fastly/cli/pkg/config"
"github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/text"
"github.com/fastly/go-fastly/fastly"
)

// CreateCommand calls the Fastly API to create Elasticsearch logging endpoints.
type CreateCommand struct {
common.Base
manifest manifest.Data

// required
EndpointName string // Can't shaddow common.Base method Name().
Version int
Index string
URL string

// optional
Pipeline common.OptionalString
RequestMaxEntries common.OptionalUint
RequestMaxBytes common.OptionalUint
User common.OptionalString
Password common.OptionalString
TLSCACert common.OptionalString
TLSClientCert common.OptionalString
TLSClientKey common.OptionalString
TLSHostname common.OptionalString
Format common.OptionalString
FormatVersion common.OptionalUint
Placement common.OptionalString
ResponseCondition common.OptionalString
}

// NewCreateCommand returns a usable command registered under the parent.
func NewCreateCommand(parent common.Registerer, globals *config.Data) *CreateCommand {
var c CreateCommand
c.Globals = globals
c.manifest.File.Read(manifest.Filename)
c.CmdClause = parent.Command("create", "Create an Elasticsearch logging endpoint on a Fastly service version").Alias("add")

c.CmdClause.Flag("name", "The name of the Elasticsearch logging object. Used as a primary key for API access").Short('n').Required().StringVar(&c.EndpointName)
c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID)
c.CmdClause.Flag("version", "Number of service version").Required().IntVar(&c.Version)

c.CmdClause.Flag("index", `The name of the Elasticsearch index to send documents (logs) to. The index must follow the Elasticsearch index format rules (https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html). We support strftime (http://man7.org/linux/man-pages/man3/strftime.3.html) interpolated variables inside braces prefixed with a pound symbol. For example, #{%F} will interpolate as YYYY-MM-DD with today's date`).Required().StringVar(&c.Index)
c.CmdClause.Flag("url", "The URL to stream logs to. Must use HTTPS.").Required().StringVar(&c.URL)

c.CmdClause.Flag("pipeline", "The ID of the Elasticsearch ingest pipeline to apply pre-process transformations to before indexing. For example my_pipeline_id. Learn more about creating a pipeline in the Elasticsearch docs (https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest.html)").Action(c.Password.Set).StringVar(&c.Pipeline.Value)
c.CmdClause.Flag("tls-ca-cert", "A secure certificate to authenticate the server with. Must be in PEM format").Action(c.TLSCACert.Set).StringVar(&c.TLSCACert.Value)
c.CmdClause.Flag("tls-client-cert", "The client certificate used to make authenticated requests. Must be in PEM format").Action(c.TLSClientCert.Set).StringVar(&c.TLSClientCert.Value)
c.CmdClause.Flag("tls-client-key", "The client private key used to make authenticated requests. Must be in PEM format").Action(c.TLSClientKey.Set).StringVar(&c.TLSClientKey.Value)
c.CmdClause.Flag("tls-hostname", "The hostname used to verify the server's certificate. It can either be the Common Name or a Subject Alternative Name (SAN)").Action(c.TLSHostname.Set).StringVar(&c.TLSHostname.Value)
c.CmdClause.Flag("format", "Apache style log formatting. Your log must produce valid JSON that Elasticsearch can ingest").Action(c.Format.Set).StringVar(&c.Format.Value)
c.CmdClause.Flag("format-version", "The version of the custom logging format used for the configured endpoint. Can be either 2 (default) or 1").Action(c.FormatVersion.Set).UintVar(&c.FormatVersion.Value)
c.CmdClause.Flag("placement", "Where in the generated VCL the logging call should be placed, overriding any format_version default. Can be none or waf_debug").Action(c.Placement.Set).StringVar(&c.Placement.Value)
c.CmdClause.Flag("response-condition", "The name of an existing condition in the configured endpoint, or leave blank to always execute").Action(c.ResponseCondition.Set).StringVar(&c.ResponseCondition.Value)
c.CmdClause.Flag("request-max-entries", "Maximum number of logs to append to a batch, if non-zero. Defaults to 0 for unbounded").Action(c.RequestMaxEntries.Set).UintVar(&c.RequestMaxEntries.Value)
c.CmdClause.Flag("request-max-bytes", "Maximum size of log batch, if non-zero. Defaults to 0 for unbounded").Action(c.RequestMaxBytes.Set).UintVar(&c.RequestMaxBytes.Value)

return &c
}

// createInput transforms values parsed from CLI flags into an object to be used by the API client library.
func (c *CreateCommand) createInput() (*fastly.CreateElasticsearchInput, error) {
var input fastly.CreateElasticsearchInput

serviceID, source := c.manifest.ServiceID()
if source == manifest.SourceUndefined {
return nil, errors.ErrNoServiceID
}

input.Service = serviceID
input.Version = c.Version
input.Name = fastly.String(c.EndpointName)
input.Index = fastly.String(c.Index)
input.URL = fastly.String(c.URL)

if c.Pipeline.Valid {
input.Pipeline = fastly.String(c.Pipeline.Value)
}

if c.RequestMaxEntries.Valid {
input.RequestMaxEntries = fastly.Uint(c.RequestMaxEntries.Value)
}

if c.RequestMaxBytes.Valid {
input.RequestMaxBytes = fastly.Uint(c.RequestMaxBytes.Value)
}

if c.User.Valid {
input.User = fastly.String(c.User.Value)
}

if c.Password.Valid {
input.Password = fastly.String(c.Password.Value)
}

if c.TLSCACert.Valid {
input.TLSCACert = fastly.String(c.TLSCACert.Value)
}

if c.TLSClientCert.Valid {
input.TLSClientCert = fastly.String(c.TLSClientCert.Value)
}

if c.TLSClientKey.Valid {
input.TLSClientKey = fastly.String(c.TLSClientKey.Value)
}

if c.TLSHostname.Valid {
input.TLSHostname = fastly.String(c.TLSHostname.Value)
}

if c.Format.Valid {
input.Format = fastly.String(c.Format.Value)
}

if c.FormatVersion.Valid {
input.FormatVersion = fastly.Uint(c.FormatVersion.Value)
}

if c.ResponseCondition.Valid {
input.ResponseCondition = fastly.String(c.ResponseCondition.Value)
}

if c.Placement.Valid {
input.Placement = fastly.String(c.Placement.Value)
}

return &input, nil
}

// Exec invokes the application logic for the command.
func (c *CreateCommand) Exec(in io.Reader, out io.Writer) error {
input, err := c.createInput()
if err != nil {
return err
}

d, err := c.Globals.Client.CreateElasticsearch(input)
if err != nil {
return err
}

text.Success(out, "Created Elasticsearch logging endpoint %s (service %s version %d)", d.Name, d.ServiceID, d.Version)
return nil
}
47 changes: 47 additions & 0 deletions pkg/logging/elasticsearch/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package elasticsearch

import (
"io"

"github.com/fastly/cli/pkg/common"
"github.com/fastly/cli/pkg/compute/manifest"
"github.com/fastly/cli/pkg/config"
"github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/text"
"github.com/fastly/go-fastly/fastly"
)

// DeleteCommand calls the Fastly API to delete Elasticsearch logging endpoints.
type DeleteCommand struct {
common.Base
manifest manifest.Data
Input fastly.DeleteElasticsearchInput
}

// NewDeleteCommand returns a usable command registered under the parent.
func NewDeleteCommand(parent common.Registerer, globals *config.Data) *DeleteCommand {
var c DeleteCommand
c.Globals = globals
c.manifest.File.Read(manifest.Filename)
c.CmdClause = parent.Command("delete", "Delete an Elasticsearch logging endpoint on a Fastly service version").Alias("remove")
c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID)
c.CmdClause.Flag("version", "Number of service version").Required().IntVar(&c.Input.Version)
c.CmdClause.Flag("name", "The name of the Elasticsearch logging object").Short('n').Required().StringVar(&c.Input.Name)
return &c
}

// Exec invokes the application logic for the command.
func (c *DeleteCommand) Exec(in io.Reader, out io.Writer) error {
serviceID, source := c.manifest.ServiceID()
if source == manifest.SourceUndefined {
return errors.ErrNoServiceID
}
c.Input.Service = serviceID

if err := c.Globals.Client.DeleteElasticsearch(&c.Input); err != nil {
return err
}

text.Success(out, "Deleted Elasticsearch logging endpoint %s (service %s version %d)", c.Input.Name, c.Input.Service, c.Input.Version)
return nil
}
Loading