Repository: saymedia/journald-cloudwatch-logs Branch: master Commit: df8eb69f89f8 Files: 130 Total size: 844.8 KB Directory structure: gitextract_n0ym8b82/ ├── README.md ├── config.go ├── journal.go ├── main.go ├── reader.go ├── record.go ├── state.go ├── terminate.go ├── unmarshal.go ├── vendor/ │ ├── github.com/ │ │ ├── aws/ │ │ │ └── aws-sdk-go/ │ │ │ ├── LICENSE.txt │ │ │ ├── NOTICE.txt │ │ │ ├── aws/ │ │ │ │ ├── awserr/ │ │ │ │ │ ├── error.go │ │ │ │ │ └── types.go │ │ │ │ ├── awsutil/ │ │ │ │ │ ├── copy.go │ │ │ │ │ ├── equal.go │ │ │ │ │ ├── path_value.go │ │ │ │ │ ├── prettify.go │ │ │ │ │ └── string_value.go │ │ │ │ ├── client/ │ │ │ │ │ ├── client.go │ │ │ │ │ ├── default_retryer.go │ │ │ │ │ └── metadata/ │ │ │ │ │ └── client_info.go │ │ │ │ ├── config.go │ │ │ │ ├── convert_types.go │ │ │ │ ├── corehandlers/ │ │ │ │ │ ├── handlers.go │ │ │ │ │ └── param_validator.go │ │ │ │ ├── credentials/ │ │ │ │ │ ├── chain_provider.go │ │ │ │ │ ├── credentials.go │ │ │ │ │ ├── ec2rolecreds/ │ │ │ │ │ │ └── ec2_role_provider.go │ │ │ │ │ ├── endpointcreds/ │ │ │ │ │ │ └── provider.go │ │ │ │ │ ├── env_provider.go │ │ │ │ │ ├── example.ini │ │ │ │ │ ├── shared_credentials_provider.go │ │ │ │ │ ├── static_provider.go │ │ │ │ │ └── stscreds/ │ │ │ │ │ └── assume_role_provider.go │ │ │ │ ├── defaults/ │ │ │ │ │ └── defaults.go │ │ │ │ ├── ec2metadata/ │ │ │ │ │ ├── api.go │ │ │ │ │ └── service.go │ │ │ │ ├── errors.go │ │ │ │ ├── logger.go │ │ │ │ ├── request/ │ │ │ │ │ ├── handlers.go │ │ │ │ │ ├── http_request.go │ │ │ │ │ ├── http_request_1_4.go │ │ │ │ │ ├── offset_reader.go │ │ │ │ │ ├── request.go │ │ │ │ │ ├── request_pagination.go │ │ │ │ │ ├── retryer.go │ │ │ │ │ └── validation.go │ │ │ │ ├── session/ │ │ │ │ │ ├── doc.go │ │ │ │ │ ├── env_config.go │ │ │ │ │ ├── session.go │ │ │ │ │ └── shared_config.go │ │ │ │ ├── signer/ │ │ │ │ │ └── v4/ │ │ │ │ │ ├── header_rules.go │ │ │ │ │ └── v4.go │ │ │ │ ├── types.go │ │ │ │ └── version.go │ │ │ ├── private/ │ │ │ │ ├── endpoints/ │ │ │ │ │ ├── endpoints.go │ │ │ │ │ ├── endpoints.json │ │ │ │ │ └── endpoints_map.go │ │ │ │ └── protocol/ │ │ │ │ ├── idempotency.go │ │ │ │ ├── json/ │ │ │ │ │ └── jsonutil/ │ │ │ │ │ ├── build.go │ │ │ │ │ └── unmarshal.go │ │ │ │ ├── jsonrpc/ │ │ │ │ │ └── jsonrpc.go │ │ │ │ ├── query/ │ │ │ │ │ ├── build.go │ │ │ │ │ ├── queryutil/ │ │ │ │ │ │ └── queryutil.go │ │ │ │ │ ├── unmarshal.go │ │ │ │ │ └── unmarshal_error.go │ │ │ │ ├── rest/ │ │ │ │ │ ├── build.go │ │ │ │ │ ├── payload.go │ │ │ │ │ └── unmarshal.go │ │ │ │ ├── unmarshal.go │ │ │ │ └── xml/ │ │ │ │ └── xmlutil/ │ │ │ │ ├── build.go │ │ │ │ ├── unmarshal.go │ │ │ │ └── xml_to_struct.go │ │ │ └── service/ │ │ │ ├── cloudwatchlogs/ │ │ │ │ ├── api.go │ │ │ │ └── service.go │ │ │ └── sts/ │ │ │ ├── api.go │ │ │ ├── customizations.go │ │ │ └── service.go │ │ ├── coreos/ │ │ │ ├── go-systemd/ │ │ │ │ ├── LICENSE │ │ │ │ └── sdjournal/ │ │ │ │ ├── functions.go │ │ │ │ ├── journal.go │ │ │ │ └── read.go │ │ │ └── pkg/ │ │ │ ├── LICENSE │ │ │ ├── NOTICE │ │ │ └── dlopen/ │ │ │ ├── dlopen.go │ │ │ └── dlopen_example.go │ │ ├── go-ini/ │ │ │ └── ini/ │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── README_ZH.md │ │ │ ├── error.go │ │ │ ├── ini.go │ │ │ ├── key.go │ │ │ ├── parser.go │ │ │ ├── section.go │ │ │ └── struct.go │ │ ├── hashicorp/ │ │ │ └── hcl/ │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── appveyor.yml │ │ │ ├── decoder.go │ │ │ ├── hcl/ │ │ │ │ ├── ast/ │ │ │ │ │ ├── ast.go │ │ │ │ │ └── walk.go │ │ │ │ ├── parser/ │ │ │ │ │ ├── error.go │ │ │ │ │ └── parser.go │ │ │ │ ├── scanner/ │ │ │ │ │ └── scanner.go │ │ │ │ ├── strconv/ │ │ │ │ │ └── quote.go │ │ │ │ └── token/ │ │ │ │ ├── position.go │ │ │ │ └── token.go │ │ │ ├── hcl.go │ │ │ ├── json/ │ │ │ │ ├── parser/ │ │ │ │ │ ├── flatten.go │ │ │ │ │ └── parser.go │ │ │ │ ├── scanner/ │ │ │ │ │ └── scanner.go │ │ │ │ └── token/ │ │ │ │ ├── position.go │ │ │ │ └── token.go │ │ │ ├── lex.go │ │ │ └── parse.go │ │ └── jmespath/ │ │ └── go-jmespath/ │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── api.go │ │ ├── astnodetype_string.go │ │ ├── functions.go │ │ ├── interpreter.go │ │ ├── lexer.go │ │ ├── parser.go │ │ ├── toktype_string.go │ │ └── util.go │ └── vendor.json └── writer.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # journald-cloudwatch-logs This small utility monitors the systemd journal, managed by `journald`, and writes journal entries into [AWS Cloudwatch Logs](https://aws.amazon.com/cloudwatch/details/#log-monitoring). This program is an alternative to the AWS-provided logs agent. The official logs agent copies data from on-disk text log files into Cloudwatch, while this utility reads directly from the systemd journal. The journal event data is written to Cloudwatch Logs in JSON format, making it amenable to filtering using the JSON filter syntax. Log records are translated to Cloudwatch JSON events using a structure like the following: ```js { "instanceId": "i-xxxxxxxx", "pid": 12354, "uid": 0, "gid": 0, "cmdName": "cron", "exe": "/usr/sbin/cron", "cmdLine": "/usr/sbin/CRON -f", "systemdUnit": "cron.service", "bootId": "fa58079c7a6d12345678b6ebf1234567", "hostname": "ip-10-1-0-15", "transport": "syslog", "priority": "INFO", "message": "pam_unix(cron:session): session opened for user root by (uid=0)", "syslog": { "facility": 10, "ident": "CRON", "pid": 12354 }, "kernel": {} } ``` The JSON-formatted log events could also be exported into an AWS ElasticSearch instance using the built-in sync mechanism, to obtain more elaborate filtering and query capabilities. ## Installation If you have a binary distribution, you just need to drop the executable file somewhere. This tool assumes that it is running on an EC2 instance. This tool uses `libsystemd` to access the journal. systemd-based distributions generally ship with this already installed, but if yours doesn't you must manually install the library somehow before this tool will work. ## Configuration This tool uses a small configuration file to set some values that are required for its operation. Most of the configuration values are optional and have default settings, but a couple are required. The configuration file uses a syntax like this: ```js log_group = "my-awesome-app" // (you'll need to create this directory before starting the program) state_file = "/var/lib/journald-cloudwatch-logs/state" ``` The following configuration settings are supported: * `aws_region`: (Optional) The AWS region whose CloudWatch Logs API will be written to. If not provided, this defaults to the region where the host EC2 instance is running. * `ec2_instance_id`: (Optional) The id of the EC2 instance on which the tool is running. There is very little reason to set this, since it will be automatically set to the id of the host EC2 instance. * `journal_dir`: (Optional) Override the directory where the systemd journal can be found. This is useful in conjunction with remote log aggregation, to work with journals synced from other systems. The default is to use the local system's journal. * `log_group`: (Required) The name of the cloudwatch log group to write logs into. This log group must be created before running the program. * `log_priority`: (Optional) The highest priority of the log messages to read (on a 0-7 scale). This defaults to DEBUG (all messages). This has a behaviour similar to `journalctl -p `. At the moment, only a single value can be specified, not a range. Possible values are: `0,1,2,3,4,5,6,7` or one of the corresponding `"emerg", "alert", "crit", "err", "warning", "notice", "info", "debug"`. When a single log level is specified, all messages with this log level or a lower (hence more important) log level are read and pushed to CloudWatch. For more information about priority levels, look at https://www.freedesktop.org/software/systemd/man/journalctl.html * `log_stream`: (Optional) The name of the cloudwatch log stream to write logs into. This defaults to the EC2 instance id. Each running instance of this application (along with any other applications writing logs into the same log group) must have a unique `log_stream` value. If the given log stream doesn't exist then it will be created before writing the first set of journal events. * `state_file`: (Required) Path to a location where the program can write, and later read, some state it needs to preserve between runs. (The format of this file is an implementation detail.) * `buffer_size`: (Optional) The size of the local event buffer where journal events will be kept in order to write batches of events to the CloudWatch Logs API. The default is 100. A batch of new events will be written to CloudWatch Logs every second even if the buffer does not fill, but this setting provides a maximum batch size to use when clearing a large backlog of events, e.g. from system boot when the program starts for the first time. Additionally values in the configuration file can contain variable expansions of the form ${instance.} which will be exapnded from the AWS Instance Identity Document or ${env.} which will be expanded from the operating system environment variables, if a key does not exist it expands to the empty string. At the time of writing, in early 2017, the supported InstanceIdentityDocument variables are: * `${instance.AvailabilityZone}`: The name of the availability zone the instance is running, eg `ap-southeast-2b` * `${instance.PrivateIP}`: The AWS internal private IP address of the instance, eg `172.1.2.3` * `${instance.Version}`: The version of the InstanceIdentityDocument definition?, eg `2010-08-31` * `${instance.Region}`: The name of the region the instance is running in, eg `ap-southeast-2` * `${instance.InstanceID}`: The instance identifier, eg `i-0123456789abcdef0` * `${instance.InstanceType}`: The type of the instance, eg `x1.32xlarge` * `${instance.AccountID}`: The amazon web services account the instance is running under, eg `098765432123` * `${instance.ImageID}`: The AMI (image) id the instance was launched from, eg `ami-a1b2c3d4` * `${instance.KernelID}`: The kernel ID used to launch the instance (PV instances only) * `${instance.RamdiskID}`: The ramdisk ID used to launch the instance (PV instances only) * `${instance.Architecture}`: The CPU architecture of the instance, eg `x86_64` ### AWS API access This program requires access to call some of the Cloudwatch API functions. The recommended way to achieve this is to create an [IAM Instance Profile](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html) that grants your EC2 instance a role that has Cloudwatch API access. The program will automatically discover and make use of instance profile credentials. The following IAM policy grants the required access across all log groups in all regions: ```js { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": [ "arn:aws:logs:*:*:log-group:*", "arn:aws:logs:*:*:log-group:*:log-stream:*" ] } ] } ``` In more complex environments you may want to restrict further which regions, groups and streams the instance can write to. You can do this by adjusting the two ARN strings in the `"Resource"` section: * The first `*` in each string can be replaced with an AWS region name like `us-east-1` to grant access only within the given region. * The `*` after `log-group` in each string can be replaced with a Cloudwatch Logs log group name to grant access only to the named group. * The `*` after `log-stream` in the second string can be replaced with a Cloudwatch Logs log stream name to grant access only to the named stream. Other combinations are possible too. For more information, see [the reference on ARNs and namespaces](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arn-syntax-cloudwatch-logs). ### Coexisting with the official Cloudwatch Logs agent This application can run on the same host as the official Cloudwatch Logs agent but care must be taken to ensure that they each use a different log stream name. Only one process may write into each log stream. ## Running on System Boot This program is best used as a persistent service that starts on boot and keeps running until the system is shut down. If you're using `journald` then you're presumably using systemd; you can create a systemd unit for this service. For example: ``` [Unit] Description=journald-cloudwatch-logs Wants=basic.target After=basic.target network.target [Service] User=nobody Group=nobody ExecStart=/usr/local/bin/journald-cloudwatch-logs /usr/local/etc/journald-cloudwatch-logs.conf KillMode=process Restart=on-failure RestartSec=42s ``` This program is designed under the assumption that it will run constantly from some point during system boot until the system shuts down. If the service is stopped while the system is running and then later started again, it will "lose" any journal entries that were written while it wasn't running. However, on the initial run after each boot it will clear the backlog of logs created during the boot process, so it is not necessary to run the program particularly early in the boot process unless you wish to *promptly* capture startup messages. ## Licence Copyright (c) 2015 Say Media Inc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: config.go ================================================ package main import ( "fmt" "io/ioutil" "os" "reflect" "strings" "github.com/aws/aws-sdk-go/aws" awsCredentials "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go/aws/ec2metadata" awsSession "github.com/aws/aws-sdk-go/aws/session" "github.com/hashicorp/hcl" ) type Config struct { AWSCredentials *awsCredentials.Credentials AWSRegion string EC2InstanceId string LogGroupName string LogStreamName string LogPriority Priority StateFilename string JournalDir string BufferSize int } type fileConfig struct { AWSRegion string `hcl:"aws_region"` EC2InstanceId string `hcl:"ec2_instance_id"` LogGroupName string `hcl:"log_group"` LogStreamName string `hcl:"log_stream"` LogPriority string `hcl:"log_priority"` StateFilename string `hcl:"state_file"` JournalDir string `hcl:"journal_dir"` BufferSize int `hcl:"buffer_size"` } func getLogLevel(priority string) (Priority, error) { logLevels := map[Priority][]string{ EMERGENCY: {"0", "emerg"}, ALERT: {"1", "alert"}, CRITICAL: {"2", "crit"}, ERROR: {"3", "err"}, WARNING: {"4", "warning"}, NOTICE: {"5", "notice"}, INFO: {"6", "info"}, DEBUG: {"7", "debug"}, } for i, s := range logLevels { if s[0] == priority || s[1] == priority { return i, nil } } return DEBUG, fmt.Errorf("'%s' is unsupported log priority", priority) } func LoadConfig(filename string) (*Config, error) { configBytes, err := ioutil.ReadFile(filename) if err != nil { return nil, err } var fConfig fileConfig err = hcl.Decode(&fConfig, string(configBytes)) if err != nil { return nil, err } if fConfig.LogGroupName == "" { return nil, fmt.Errorf("log_group is required") } if fConfig.StateFilename == "" { return nil, fmt.Errorf("state_file is required") } metaClient := ec2metadata.New(awsSession.New(&aws.Config{})) expandFileConfig(&fConfig, metaClient) config := &Config{} if fConfig.AWSRegion != "" { config.AWSRegion = fConfig.AWSRegion } else { region, err := metaClient.Region() if err != nil { return nil, fmt.Errorf("unable to detect AWS region: %s", err) } config.AWSRegion = region } if fConfig.EC2InstanceId != "" { config.EC2InstanceId = fConfig.EC2InstanceId } else { instanceId, err := metaClient.GetMetadata("instance-id") if err != nil { return nil, fmt.Errorf("unable to detect EC2 instance id: %s", err) } config.EC2InstanceId = instanceId } if fConfig.LogPriority == "" { // Log everything config.LogPriority = DEBUG } else { config.LogPriority, err = getLogLevel(fConfig.LogPriority) if err != nil { return nil, fmt.Errorf("The provided log filtering '%s' is unsupported by systemd!", fConfig.LogPriority) } } config.LogGroupName = fConfig.LogGroupName if fConfig.LogStreamName != "" { config.LogStreamName = fConfig.LogStreamName } else { // By default we use the instance id as the stream name. config.LogStreamName = config.EC2InstanceId } config.StateFilename = fConfig.StateFilename config.JournalDir = fConfig.JournalDir if fConfig.BufferSize != 0 { config.BufferSize = fConfig.BufferSize } else { config.BufferSize = 100 } config.AWSCredentials = awsCredentials.NewChainCredentials([]awsCredentials.Provider{ &awsCredentials.EnvProvider{}, &ec2rolecreds.EC2RoleProvider{ Client: metaClient, }, }) return config, nil } func (c *Config) NewAWSSession() *awsSession.Session { config := &aws.Config{ Credentials: c.AWSCredentials, Region: aws.String(c.AWSRegion), MaxRetries: aws.Int(3), } return awsSession.New(config) } /* * Expand variables of the form $Foo or ${Foo} in the user provided config * from the EC2Metadata Instance Identity Document * [ https://docs.aws.amazon.com/sdk-for-go/api/aws/ec2metadata/#EC2InstanceIdentityDocument ] * or the environment */ func expandFileConfig(config *fileConfig, metaClient *ec2metadata.EC2Metadata) { vars := make(map[string]string) // If we can fetch the InstanceIdentityDocument then iterate over the // struct extracting the string fields and their values into the vars map data, err := metaClient.GetInstanceIdentityDocument() if err == nil { metadata := reflect.ValueOf( data ) for i := 0; i < metadata.NumField(); i++ { field := metadata.Field(i) ftype := metadata.Type().Field(i) if (field.Type() != reflect.TypeOf("")) { continue } vars[ftype.Name] = fmt.Sprintf("%v", field.Interface()) } } // Iterate over all the string fields in the fileConfig struct performing // Variable expansion on them, with EC2 Instance Identity fields overriding // the OS environment rconfig := reflect.ValueOf(config) for i := 0; i < rconfig.Elem().NumField(); i++ { field := rconfig.Elem().Field(i) if field.Type() != reflect.TypeOf("") { continue } val := field.Interface().(string) if val != "" { field.SetString( expandBraceVars( val, func(varname string) string { if strings.HasPrefix(varname, "instance.") { if val, exists := vars[strings.TrimPrefix(varname, "instance.")]; exists { return val } // Unknown key => empty string return "" } else if (strings.HasPrefix(varname, "env.")) { return os.Getenv(strings.TrimPrefix(varname, "env.")) } else { // Unknown prefix => empty string return "" } }, ), ) } } } // Modified version of os.Expand() that only expands ${name} and not $name func expandBraceVars(s string, mapping func(string) string) string { buf := make([]byte, 0, 2*len(s)) // ${} is all ASCII, so bytes are fine for this operation. i := 0 for j := 0; j < len(s); j++ { if s[j] == '$' && j+3 < len(s) && s[j+1] == '{' { buf = append(buf, s[i:j]...) idx := strings.Index(s[j+2:], "}") if (idx >= 0) { // We have a full ${name} string buf = append(buf, mapping(s[j+2:j+2+idx])...) j += 2+idx } else { // We ran out of string (unclosed ${) return string(buf) } i = j + 1 } } return string(buf) + s[i:] } ================================================ FILE: journal.go ================================================ package main import ( "github.com/coreos/go-systemd/sdjournal" "strconv" ) func AddLogFilters(journal *sdjournal.Journal, config *Config) { // Add Priority Filters if config.LogPriority < DEBUG { for p, _ := range PriorityJSON { if p <= config.LogPriority { journal.AddMatch("PRIORITY=" + strconv.Itoa(int(p))) } } journal.AddDisjunction() } } ================================================ FILE: main.go ================================================ package main import ( "flag" "fmt" "log" "os" "github.com/coreos/go-systemd/sdjournal" ) var help = flag.Bool("help", false, "set to true to show this help") func main() { flag.Parse() if *help { usage() os.Exit(0) } configFilename := flag.Arg(0) if configFilename == "" { usage() os.Exit(1) } err := run(configFilename) if err != nil { os.Stderr.WriteString(err.Error()) os.Stderr.Write([]byte{'\n'}) os.Exit(2) } } func usage() { os.Stderr.WriteString("Usage: journald-cloudwatch-logs \n\n") flag.PrintDefaults() os.Stderr.WriteString("\n") } func run(configFilename string) error { config, err := LoadConfig(configFilename) if err != nil { return fmt.Errorf("error reading config: %s", err) } var journal *sdjournal.Journal if config.JournalDir == "" { journal, err = sdjournal.NewJournal() } else { log.Printf("using journal dir: %s", config.JournalDir) journal, err = sdjournal.NewJournalFromDir(config.JournalDir) } if err != nil { return fmt.Errorf("error opening journal: %s", err) } defer journal.Close() AddLogFilters(journal, config) state, err := OpenState(config.StateFilename) if err != nil { return fmt.Errorf("Failed to open %s: %s", config.StateFilename, err) } lastBootId, nextSeq := state.LastState() awsSession := config.NewAWSSession() writer, err := NewWriter( awsSession, config.LogGroupName, config.LogStreamName, nextSeq, ) if err != nil { return fmt.Errorf("error initializing writer: %s", err) } seeked, err := journal.Next() if seeked == 0 || err != nil { return fmt.Errorf("unable to seek to first item in journal") } bootId, err := journal.GetData("_BOOT_ID") bootId = bootId[9:] // Trim off "_BOOT_ID=" prefix // If the boot id has changed since our last run then we'll start from // the beginning of the stream, but if we're starting up with the same // boot id then we'll seek to the end of the stream to avoid repeating // anything. However, we will miss any items that were added while we // weren't running. skip := uint64(0) if bootId == lastBootId { // If we're still in the same "boot" as we were last time then // we were stopped and started again, so we'll seek to the last // item in the log as an approximation of resuming streaming, // though we will miss any logs that were added while we were // running. journal.SeekTail() // Skip the last item so our log will resume only when we get // the *next item. skip = 1 } err = state.SetState(bootId, nextSeq) if err != nil { return fmt.Errorf("Failed to write state: %s", err) } bufSize := config.BufferSize records := make(chan Record) batches := make(chan []Record) go ReadRecords(config.EC2InstanceId, journal, records, skip) go BatchRecords(records, batches, bufSize) for batch := range batches { nextSeq, err = writer.WriteBatch(batch) if err != nil { return fmt.Errorf("Failed to write to cloudwatch: %s", err) } err = state.SetState(bootId, nextSeq) if err != nil { return fmt.Errorf("Failed to write state: %s", err) } } // We fall out here when interrupted by a signal. // Last chance to write the state. err = state.SetState(bootId, nextSeq) if err != nil { return fmt.Errorf("Failed to write state on exit: %s", err) } return nil } ================================================ FILE: reader.go ================================================ package main import ( "fmt" "time" "github.com/coreos/go-systemd/sdjournal" ) func ReadRecords(instanceId string, journal *sdjournal.Journal, c chan<- Record, skip uint64) { record := &Record{} termC := MakeTerminateChannel() checkTerminate := func() bool { select { case <-termC: close(c) return true default: return false } } for { if checkTerminate() { return } err := UnmarshalRecord(journal, record) if err != nil { c <- synthRecord( fmt.Errorf("error unmarshalling record: %s", err), ) continue } if skip > 0 { skip-- } else { record.InstanceId = instanceId c <- *record } for { if checkTerminate() { return } seeked, err := journal.Next() if err != nil { c <- synthRecord( fmt.Errorf("error reading from journal: %s", err), ) // It's likely that we didn't actually advance here, so // we should wait a bit so we don't spin the CPU at 100% // when we run into errors. time.Sleep(2 * time.Second) continue } if seeked == 0 { // If there's nothing new in the stream then we'll // wait for something new to show up. // FIXME: We can actually end up waiting up to 2 seconds // to gracefully terminate because of this. It'd be nicer // to stop waiting if we get a termination signal, but // this will do for now. journal.Wait(2 * time.Second) continue } break } } } // BatchRecords consumes a channel of individual records and produces // a channel of slices of record pointers in sizes up to the given // batch size. // If records don't show up fast enough, smaller batches will be returned // each second as long as at least one item is in the buffer. func BatchRecords(records <-chan Record, batches chan<- []Record, batchSize int) { // We have two buffers here so that we can fill one while the // caller is working on the other. The caller is therefore // guaranteed that the returned slice will remain valid until // the next read of the batches channel. var bufs [2][]Record bufs[0] = make([]Record, batchSize) bufs[1] = make([]Record, batchSize) var record Record var more bool currentBuf := 0 next := 0 timer := time.NewTimer(time.Second) timer.Stop() for { select { case record, more = <-records: if !more { close(batches) return } bufs[currentBuf][next] = record next++ if next < batchSize { // If we've just added our first record then we'll // start the batch timer. if next == 1 { timer.Reset(time.Second) } // Not enough records yet, so wait again. continue } break case <-timer.C: break } timer.Stop() if next == 0 { continue } // If we manage to fall out here then either the buffer is fuull // or the batch timer expired. Either way it's time for us to // emit a batch. batches <- bufs[currentBuf][0:next] // Switch buffers before we start building the next batch. currentBuf = (currentBuf + 1) % 2 next = 0 } } // synthRecord produces synthetic records to report errors, so that // we can stream our own errors directly into cloudwatch rather than // emitting them through journald and risking feedback loops. func synthRecord(err error) Record { return Record{ Command: "journald-cloudwatch-logs", Priority: ERROR, Message: err.Error(), } } ================================================ FILE: record.go ================================================ package main type Priority int var ( EMERGENCY Priority = 0 ALERT Priority = 1 CRITICAL Priority = 2 ERROR Priority = 3 WARNING Priority = 4 NOTICE Priority = 5 INFO Priority = 6 DEBUG Priority = 7 ) var PriorityJSON = map[Priority][]byte{ EMERGENCY: []byte("\"EMERG\""), ALERT: []byte("\"ALERT\""), CRITICAL: []byte("\"CRITICAL\""), ERROR: []byte("\"ERROR\""), WARNING: []byte("\"WARNING\""), NOTICE: []byte("\"NOTICE\""), INFO: []byte("\"INFO\""), DEBUG: []byte("\"DEBUG\""), } type Record struct { InstanceId string `json:"instanceId,omitempty"` TimeUsec int64 `json:"-"` PID int `json:"pid" journald:"_PID"` UID int `json:"uid" journald:"_UID"` GID int `json:"gid" journald:"_GID"` Command string `json:"cmdName,omitempty" journald:"_COMM"` Executable string `json:"exe,omitempty" journald:"_EXE"` CommandLine string `json:"cmdLine,omitempty" journald:"_CMDLINE"` SystemdUnit string `json:"systemdUnit,omitempty" journald:"_SYSTEMD_UNIT"` BootId string `json:"bootId,omitempty" journald:"_BOOT_ID"` MachineId string `json:"machineId,omitempty" journald:"_MACHINE_ID"` Hostname string `json:"hostname,omitempty" journald:"_HOSTNAME"` Transport string `json:"transport,omitempty" journald:"_TRANSPORT"` Priority Priority `json:"priority" journald:"PRIORITY"` Message string `json:"message" journald:"MESSAGE"` MessageId string `json:"messageId,omitempty" journald:"MESSAGE_ID"` Errno int `json:"machineId,omitempty" journald:"ERRNO"` Syslog RecordSyslog `json:"syslog,omitempty"` Kernel RecordKernel `json:"kernel,omitempty"` Container_Name string `json:"containerName,omitempty" journald:"CONTAINER_NAME"` Container_Tag string `json:"containerTag,omitempty" journald:"CONTAINER_TAG"` Container_ID string `json:"containerID,omitempty" journald:"CONTAINER_ID"` } type RecordSyslog struct { Facility int `json:"facility,omitempty" journald:"SYSLOG_FACILITY"` Identifier string `json:"ident,omitempty" journald:"SYSLOG_IDENTIFIER"` PID int `json:"pid,omitempty" journald:"SYSLOG_PID"` } type RecordKernel struct { Device string `json:"device,omitempty" journald:"_KERNEL_DEVICE"` Subsystem string `json:"subsystem,omitempty" journald:"_KERNEL_SUBSYSTEM"` SysName string `json:"sysName,omitempty" journald:"_UDEV_SYSNAME"` DevNode string `json:"devNode,omitempty" journald:"_UDEV_DEVNODE"` } func (p Priority) MarshalJSON() ([]byte, error) { return PriorityJSON[p], nil } ================================================ FILE: state.go ================================================ package main import ( "fmt" "os" ) const stateFormat = "%s\n%s\n" const mapSize = 64 type State struct { file *os.File } func OpenState(fn string) (State, error) { s := State{} f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0700) if err != nil { return s, err } s.file = f return s, nil } func (s State) Close() error { return s.file.Close() } func (s State) Sync() error { return s.file.Sync() } func (s State) LastState() (string, string) { var bootId string var seqToken string _, err := s.file.Seek(0, 0) if err != nil { return "", "" } n, err := fmt.Fscanf(s.file, stateFormat, &bootId, &seqToken) if err != nil || n < 2 { return "", "" } return bootId, seqToken } func (s State) SetState(bootId, seqToken string) error { _, err := s.file.Seek(0, 0) if err != nil { return err } _, err = fmt.Fprintf(s.file, stateFormat, bootId, seqToken) if err != nil { return err } return nil } ================================================ FILE: terminate.go ================================================ package main import ( "os" "os/signal" "syscall" ) // MakeTerminateChannel returns a channel that will become readable if // the process is interrupted or terminated via a signal. // // This is used to gracefully exit the reader loop, which in turn causes // the rest of the program to gracefully terminate, flushing any remaining // buffers and writing its persistent state to disk. func MakeTerminateChannel() <-chan os.Signal { ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) return ch } ================================================ FILE: unmarshal.go ================================================ package main import ( "fmt" "reflect" "strconv" "time" "github.com/coreos/go-systemd/sdjournal" ) func UnmarshalRecord(journal *sdjournal.Journal, to *Record) error { err := unmarshalRecord(journal, reflect.ValueOf(to).Elem()) if err == nil { // FIXME: Should use the realtime from the log record, // but for some reason journal.GetRealtimeUsec always fails. to.TimeUsec = time.Now().Unix() * 1000 } return err } func unmarshalRecord(journal *sdjournal.Journal, toVal reflect.Value) error { toType := toVal.Type() numField := toVal.NumField() // This intentionally supports only the few types we actually // use on the Record struct. It's not intended to be generic. for i := 0; i < numField; i++ { fieldVal := toVal.Field(i) fieldDef := toType.Field(i) fieldType := fieldDef.Type fieldTag := fieldDef.Tag fieldTypeKind := fieldType.Kind() if fieldTypeKind == reflect.Struct { // Recursively unmarshal from the same journal unmarshalRecord(journal, fieldVal) } jdKey := fieldTag.Get("journald") if jdKey == "" { continue } value, err := journal.GetData(jdKey) if err != nil || value == "" { fieldVal.Set(reflect.Zero(fieldType)) continue } // The value is returned with the key and an equals sign on // the front, so we'll trim those off. value = value[len(jdKey)+1:] switch fieldTypeKind { case reflect.Int: intVal, err := strconv.Atoi(value) if err != nil { // Should never happen, but not much we can do here. fieldVal.Set(reflect.Zero(fieldType)) continue } fieldVal.SetInt(int64(intVal)) break case reflect.String: fieldVal.SetString(value) break default: // Should never happen panic(fmt.Errorf("Can't unmarshal to %s", fieldType)) } } return nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/LICENSE.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/aws/aws-sdk-go/NOTICE.txt ================================================ AWS SDK for Go Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. Copyright 2014-2015 Stripe, Inc. ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go ================================================ // Package awserr represents API error interface accessors for the SDK. package awserr // An Error wraps lower level errors with code, message and an original error. // The underlying concrete error type may also satisfy other interfaces which // can be to used to obtain more specific information about the error. // // Calling Error() or String() will always include the full information about // an error based on its underlying type. // // Example: // // output, err := s3manage.Upload(svc, input, opts) // if err != nil { // if awsErr, ok := err.(awserr.Error); ok { // // Get error details // log.Println("Error:", awsErr.Code(), awsErr.Message()) // // // Prints out full error message, including original error if there was one. // log.Println("Error:", awsErr.Error()) // // // Get original error // if origErr := awsErr.OrigErr(); origErr != nil { // // operate on original error. // } // } else { // fmt.Println(err.Error()) // } // } // type Error interface { // Satisfy the generic error interface. error // Returns the short phrase depicting the classification of the error. Code() string // Returns the error details message. Message() string // Returns the original error if one was set. Nil is returned if not set. OrigErr() error } // BatchError is a batch of errors which also wraps lower level errors with // code, message, and original errors. Calling Error() will include all errors // that occurred in the batch. // // Deprecated: Replaced with BatchedErrors. Only defined for backwards // compatibility. type BatchError interface { // Satisfy the generic error interface. error // Returns the short phrase depicting the classification of the error. Code() string // Returns the error details message. Message() string // Returns the original error if one was set. Nil is returned if not set. OrigErrs() []error } // BatchedErrors is a batch of errors which also wraps lower level errors with // code, message, and original errors. Calling Error() will include all errors // that occurred in the batch. // // Replaces BatchError type BatchedErrors interface { // Satisfy the base Error interface. Error // Returns the original error if one was set. Nil is returned if not set. OrigErrs() []error } // New returns an Error object described by the code, message, and origErr. // // If origErr satisfies the Error interface it will not be wrapped within a new // Error object and will instead be returned. func New(code, message string, origErr error) Error { var errs []error if origErr != nil { errs = append(errs, origErr) } return newBaseError(code, message, errs) } // NewBatchError returns an BatchedErrors with a collection of errors as an // array of errors. func NewBatchError(code, message string, errs []error) BatchedErrors { return newBaseError(code, message, errs) } // A RequestFailure is an interface to extract request failure information from // an Error such as the request ID of the failed request returned by a service. // RequestFailures may not always have a requestID value if the request failed // prior to reaching the service such as a connection error. // // Example: // // output, err := s3manage.Upload(svc, input, opts) // if err != nil { // if reqerr, ok := err.(RequestFailure); ok { // log.Println("Request failed", reqerr.Code(), reqerr.Message(), reqerr.RequestID()) // } else { // log.Println("Error:", err.Error()) // } // } // // Combined with awserr.Error: // // output, err := s3manage.Upload(svc, input, opts) // if err != nil { // if awsErr, ok := err.(awserr.Error); ok { // // Generic AWS Error with Code, Message, and original error (if any) // fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr()) // // if reqErr, ok := err.(awserr.RequestFailure); ok { // // A service error occurred // fmt.Println(reqErr.StatusCode(), reqErr.RequestID()) // } // } else { // fmt.Println(err.Error()) // } // } // type RequestFailure interface { Error // The status code of the HTTP response. StatusCode() int // The request ID returned by the service for a request failure. This will // be empty if no request ID is available such as the request failed due // to a connection error. RequestID() string } // NewRequestFailure returns a new request error wrapper for the given Error // provided. func NewRequestFailure(err Error, statusCode int, reqID string) RequestFailure { return newRequestError(err, statusCode, reqID) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go ================================================ package awserr import "fmt" // SprintError returns a string of the formatted error code. // // Both extra and origErr are optional. If they are included their lines // will be added, but if they are not included their lines will be ignored. func SprintError(code, message, extra string, origErr error) string { msg := fmt.Sprintf("%s: %s", code, message) if extra != "" { msg = fmt.Sprintf("%s\n\t%s", msg, extra) } if origErr != nil { msg = fmt.Sprintf("%s\ncaused by: %s", msg, origErr.Error()) } return msg } // A baseError wraps the code and message which defines an error. It also // can be used to wrap an original error object. // // Should be used as the root for errors satisfying the awserr.Error. Also // for any error which does not fit into a specific error wrapper type. type baseError struct { // Classification of error code string // Detailed information about error message string // Optional original error this error is based off of. Allows building // chained errors. errs []error } // newBaseError returns an error object for the code, message, and errors. // // code is a short no whitespace phrase depicting the classification of // the error that is being created. // // message is the free flow string containing detailed information about the // error. // // origErrs is the error objects which will be nested under the new errors to // be returned. func newBaseError(code, message string, origErrs []error) *baseError { b := &baseError{ code: code, message: message, errs: origErrs, } return b } // Error returns the string representation of the error. // // See ErrorWithExtra for formatting. // // Satisfies the error interface. func (b baseError) Error() string { size := len(b.errs) if size > 0 { return SprintError(b.code, b.message, "", errorList(b.errs)) } return SprintError(b.code, b.message, "", nil) } // String returns the string representation of the error. // Alias for Error to satisfy the stringer interface. func (b baseError) String() string { return b.Error() } // Code returns the short phrase depicting the classification of the error. func (b baseError) Code() string { return b.code } // Message returns the error details message. func (b baseError) Message() string { return b.message } // OrigErr returns the original error if one was set. Nil is returned if no // error was set. This only returns the first element in the list. If the full // list is needed, use BatchedErrors. func (b baseError) OrigErr() error { switch len(b.errs) { case 0: return nil case 1: return b.errs[0] default: if err, ok := b.errs[0].(Error); ok { return NewBatchError(err.Code(), err.Message(), b.errs[1:]) } return NewBatchError("BatchedErrors", "multiple errors occurred", b.errs) } } // OrigErrs returns the original errors if one was set. An empty slice is // returned if no error was set. func (b baseError) OrigErrs() []error { return b.errs } // So that the Error interface type can be included as an anonymous field // in the requestError struct and not conflict with the error.Error() method. type awsError Error // A requestError wraps a request or service error. // // Composed of baseError for code, message, and original error. type requestError struct { awsError statusCode int requestID string } // newRequestError returns a wrapped error with additional information for // request status code, and service requestID. // // Should be used to wrap all request which involve service requests. Even if // the request failed without a service response, but had an HTTP status code // that may be meaningful. // // Also wraps original errors via the baseError. func newRequestError(err Error, statusCode int, requestID string) *requestError { return &requestError{ awsError: err, statusCode: statusCode, requestID: requestID, } } // Error returns the string representation of the error. // Satisfies the error interface. func (r requestError) Error() string { extra := fmt.Sprintf("status code: %d, request id: %s", r.statusCode, r.requestID) return SprintError(r.Code(), r.Message(), extra, r.OrigErr()) } // String returns the string representation of the error. // Alias for Error to satisfy the stringer interface. func (r requestError) String() string { return r.Error() } // StatusCode returns the wrapped status code for the error func (r requestError) StatusCode() int { return r.statusCode } // RequestID returns the wrapped requestID func (r requestError) RequestID() string { return r.requestID } // OrigErrs returns the original errors if one was set. An empty slice is // returned if no error was set. func (r requestError) OrigErrs() []error { if b, ok := r.awsError.(BatchedErrors); ok { return b.OrigErrs() } return []error{r.OrigErr()} } // An error list that satisfies the golang interface type errorList []error // Error returns the string representation of the error. // // Satisfies the error interface. func (e errorList) Error() string { msg := "" // How do we want to handle the array size being zero if size := len(e); size > 0 { for i := 0; i < size; i++ { msg += fmt.Sprintf("%s", e[i].Error()) // We check the next index to see if it is within the slice. // If it is, then we append a newline. We do this, because unit tests // could be broken with the additional '\n' if i+1 < size { msg += "\n" } } } return msg } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go ================================================ package awsutil import ( "io" "reflect" "time" ) // Copy deeply copies a src structure to dst. Useful for copying request and // response structures. // // Can copy between structs of different type, but will only copy fields which // are assignable, and exist in both structs. Fields which are not assignable, // or do not exist in both structs are ignored. func Copy(dst, src interface{}) { dstval := reflect.ValueOf(dst) if !dstval.IsValid() { panic("Copy dst cannot be nil") } rcopy(dstval, reflect.ValueOf(src), true) } // CopyOf returns a copy of src while also allocating the memory for dst. // src must be a pointer type or this operation will fail. func CopyOf(src interface{}) (dst interface{}) { dsti := reflect.New(reflect.TypeOf(src).Elem()) dst = dsti.Interface() rcopy(dsti, reflect.ValueOf(src), true) return } // rcopy performs a recursive copy of values from the source to destination. // // root is used to skip certain aspects of the copy which are not valid // for the root node of a object. func rcopy(dst, src reflect.Value, root bool) { if !src.IsValid() { return } switch src.Kind() { case reflect.Ptr: if _, ok := src.Interface().(io.Reader); ok { if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() { dst.Elem().Set(src) } else if dst.CanSet() { dst.Set(src) } } else { e := src.Type().Elem() if dst.CanSet() && !src.IsNil() { if _, ok := src.Interface().(*time.Time); !ok { dst.Set(reflect.New(e)) } else { tempValue := reflect.New(e) tempValue.Elem().Set(src.Elem()) // Sets time.Time's unexported values dst.Set(tempValue) } } if src.Elem().IsValid() { // Keep the current root state since the depth hasn't changed rcopy(dst.Elem(), src.Elem(), root) } } case reflect.Struct: t := dst.Type() for i := 0; i < t.NumField(); i++ { name := t.Field(i).Name srcVal := src.FieldByName(name) dstVal := dst.FieldByName(name) if srcVal.IsValid() && dstVal.CanSet() { rcopy(dstVal, srcVal, false) } } case reflect.Slice: if src.IsNil() { break } s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap()) dst.Set(s) for i := 0; i < src.Len(); i++ { rcopy(dst.Index(i), src.Index(i), false) } case reflect.Map: if src.IsNil() { break } s := reflect.MakeMap(src.Type()) dst.Set(s) for _, k := range src.MapKeys() { v := src.MapIndex(k) v2 := reflect.New(v.Type()).Elem() rcopy(v2, v, false) dst.SetMapIndex(k, v2) } default: // Assign the value if possible. If its not assignable, the value would // need to be converted and the impact of that may be unexpected, or is // not compatible with the dst type. if src.Type().AssignableTo(dst.Type()) { dst.Set(src) } } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go ================================================ package awsutil import ( "reflect" ) // DeepEqual returns if the two values are deeply equal like reflect.DeepEqual. // In addition to this, this method will also dereference the input values if // possible so the DeepEqual performed will not fail if one parameter is a // pointer and the other is not. // // DeepEqual will not perform indirection of nested values of the input parameters. func DeepEqual(a, b interface{}) bool { ra := reflect.Indirect(reflect.ValueOf(a)) rb := reflect.Indirect(reflect.ValueOf(b)) if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid { // If the elements are both nil, and of the same type the are equal // If they are of different types they are not equal return reflect.TypeOf(a) == reflect.TypeOf(b) } else if raValid != rbValid { // Both values must be valid to be equal return false } return reflect.DeepEqual(ra.Interface(), rb.Interface()) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go ================================================ package awsutil import ( "reflect" "regexp" "strconv" "strings" "github.com/jmespath/go-jmespath" ) var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`) // rValuesAtPath returns a slice of values found in value v. The values // in v are explored recursively so all nested values are collected. func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTerm bool) []reflect.Value { pathparts := strings.Split(path, "||") if len(pathparts) > 1 { for _, pathpart := range pathparts { vals := rValuesAtPath(v, pathpart, createPath, caseSensitive, nilTerm) if len(vals) > 0 { return vals } } return nil } values := []reflect.Value{reflect.Indirect(reflect.ValueOf(v))} components := strings.Split(path, ".") for len(values) > 0 && len(components) > 0 { var index *int64 var indexStar bool c := strings.TrimSpace(components[0]) if c == "" { // no actual component, illegal syntax return nil } else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] { // TODO normalize case for user return nil // don't support unexported fields } // parse this component if m := indexRe.FindStringSubmatch(c); m != nil { c = m[1] if m[2] == "" { index = nil indexStar = true } else { i, _ := strconv.ParseInt(m[2], 10, 32) index = &i indexStar = false } } nextvals := []reflect.Value{} for _, value := range values { // pull component name out of struct member if value.Kind() != reflect.Struct { continue } if c == "*" { // pull all members for i := 0; i < value.NumField(); i++ { if f := reflect.Indirect(value.Field(i)); f.IsValid() { nextvals = append(nextvals, f) } } continue } value = value.FieldByNameFunc(func(name string) bool { if c == name { return true } else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) { return true } return false }) if nilTerm && value.Kind() == reflect.Ptr && len(components[1:]) == 0 { if !value.IsNil() { value.Set(reflect.Zero(value.Type())) } return []reflect.Value{value} } if createPath && value.Kind() == reflect.Ptr && value.IsNil() { // TODO if the value is the terminus it should not be created // if the value to be set to its position is nil. value.Set(reflect.New(value.Type().Elem())) value = value.Elem() } else { value = reflect.Indirect(value) } if value.Kind() == reflect.Slice || value.Kind() == reflect.Map { if !createPath && value.IsNil() { value = reflect.ValueOf(nil) } } if value.IsValid() { nextvals = append(nextvals, value) } } values = nextvals if indexStar || index != nil { nextvals = []reflect.Value{} for _, valItem := range values { value := reflect.Indirect(valItem) if value.Kind() != reflect.Slice { continue } if indexStar { // grab all indices for i := 0; i < value.Len(); i++ { idx := reflect.Indirect(value.Index(i)) if idx.IsValid() { nextvals = append(nextvals, idx) } } continue } // pull out index i := int(*index) if i >= value.Len() { // check out of bounds if createPath { // TODO resize slice } else { continue } } else if i < 0 { // support negative indexing i = value.Len() + i } value = reflect.Indirect(value.Index(i)) if value.Kind() == reflect.Slice || value.Kind() == reflect.Map { if !createPath && value.IsNil() { value = reflect.ValueOf(nil) } } if value.IsValid() { nextvals = append(nextvals, value) } } values = nextvals } components = components[1:] } return values } // ValuesAtPath returns a list of values at the case insensitive lexical // path inside of a structure. func ValuesAtPath(i interface{}, path string) ([]interface{}, error) { result, err := jmespath.Search(path, i) if err != nil { return nil, err } v := reflect.ValueOf(result) if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) { return nil, nil } if s, ok := result.([]interface{}); ok { return s, err } if v.Kind() == reflect.Map && v.Len() == 0 { return nil, nil } if v.Kind() == reflect.Slice { out := make([]interface{}, v.Len()) for i := 0; i < v.Len(); i++ { out[i] = v.Index(i).Interface() } return out, nil } return []interface{}{result}, nil } // SetValueAtPath sets a value at the case insensitive lexical path inside // of a structure. func SetValueAtPath(i interface{}, path string, v interface{}) { if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != nil { for _, rval := range rvals { if rval.Kind() == reflect.Ptr && rval.IsNil() { continue } setValue(rval, v) } } } func setValue(dstVal reflect.Value, src interface{}) { if dstVal.Kind() == reflect.Ptr { dstVal = reflect.Indirect(dstVal) } srcVal := reflect.ValueOf(src) if !srcVal.IsValid() { // src is literal nil if dstVal.CanAddr() { // Convert to pointer so that pointer's value can be nil'ed // dstVal = dstVal.Addr() } dstVal.Set(reflect.Zero(dstVal.Type())) } else if srcVal.Kind() == reflect.Ptr { if srcVal.IsNil() { srcVal = reflect.Zero(dstVal.Type()) } else { srcVal = reflect.ValueOf(src).Elem() } dstVal.Set(srcVal) } else { dstVal.Set(srcVal) } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go ================================================ package awsutil import ( "bytes" "fmt" "io" "reflect" "strings" ) // Prettify returns the string representation of a value. func Prettify(i interface{}) string { var buf bytes.Buffer prettify(reflect.ValueOf(i), 0, &buf) return buf.String() } // prettify will recursively walk value v to build a textual // representation of the value. func prettify(v reflect.Value, indent int, buf *bytes.Buffer) { for v.Kind() == reflect.Ptr { v = v.Elem() } switch v.Kind() { case reflect.Struct: strtype := v.Type().String() if strtype == "time.Time" { fmt.Fprintf(buf, "%s", v.Interface()) break } else if strings.HasPrefix(strtype, "io.") { buf.WriteString("") break } buf.WriteString("{\n") names := []string{} for i := 0; i < v.Type().NumField(); i++ { name := v.Type().Field(i).Name f := v.Field(i) if name[0:1] == strings.ToLower(name[0:1]) { continue // ignore unexported fields } if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() { continue // ignore unset fields } names = append(names, name) } for i, n := range names { val := v.FieldByName(n) buf.WriteString(strings.Repeat(" ", indent+2)) buf.WriteString(n + ": ") prettify(val, indent+2, buf) if i < len(names)-1 { buf.WriteString(",\n") } } buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") case reflect.Slice: nl, id, id2 := "", "", "" if v.Len() > 3 { nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2) } buf.WriteString("[" + nl) for i := 0; i < v.Len(); i++ { buf.WriteString(id2) prettify(v.Index(i), indent+2, buf) if i < v.Len()-1 { buf.WriteString("," + nl) } } buf.WriteString(nl + id + "]") case reflect.Map: buf.WriteString("{\n") for i, k := range v.MapKeys() { buf.WriteString(strings.Repeat(" ", indent+2)) buf.WriteString(k.String() + ": ") prettify(v.MapIndex(k), indent+2, buf) if i < v.Len()-1 { buf.WriteString(",\n") } } buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") default: if !v.IsValid() { fmt.Fprint(buf, "") return } format := "%v" switch v.Interface().(type) { case string: format = "%q" case io.ReadSeeker, io.Reader: format = "buffer(%p)" } fmt.Fprintf(buf, format, v.Interface()) } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go ================================================ package awsutil import ( "bytes" "fmt" "reflect" "strings" ) // StringValue returns the string representation of a value. func StringValue(i interface{}) string { var buf bytes.Buffer stringValue(reflect.ValueOf(i), 0, &buf) return buf.String() } func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) { for v.Kind() == reflect.Ptr { v = v.Elem() } switch v.Kind() { case reflect.Struct: buf.WriteString("{\n") names := []string{} for i := 0; i < v.Type().NumField(); i++ { name := v.Type().Field(i).Name f := v.Field(i) if name[0:1] == strings.ToLower(name[0:1]) { continue // ignore unexported fields } if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() { continue // ignore unset fields } names = append(names, name) } for i, n := range names { val := v.FieldByName(n) buf.WriteString(strings.Repeat(" ", indent+2)) buf.WriteString(n + ": ") stringValue(val, indent+2, buf) if i < len(names)-1 { buf.WriteString(",\n") } } buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") case reflect.Slice: nl, id, id2 := "", "", "" if v.Len() > 3 { nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2) } buf.WriteString("[" + nl) for i := 0; i < v.Len(); i++ { buf.WriteString(id2) stringValue(v.Index(i), indent+2, buf) if i < v.Len()-1 { buf.WriteString("," + nl) } } buf.WriteString(nl + id + "]") case reflect.Map: buf.WriteString("{\n") for i, k := range v.MapKeys() { buf.WriteString(strings.Repeat(" ", indent+2)) buf.WriteString(k.String() + ": ") stringValue(v.MapIndex(k), indent+2, buf) if i < v.Len()-1 { buf.WriteString(",\n") } } buf.WriteString("\n" + strings.Repeat(" ", indent) + "}") default: format := "%v" switch v.Interface().(type) { case string: format = "%q" } fmt.Fprintf(buf, format, v.Interface()) } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/client/client.go ================================================ package client import ( "fmt" "io/ioutil" "net/http/httputil" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/client/metadata" "github.com/aws/aws-sdk-go/aws/request" ) // A Config provides configuration to a service client instance. type Config struct { Config *aws.Config Handlers request.Handlers Endpoint, SigningRegion string } // ConfigProvider provides a generic way for a service client to receive // the ClientConfig without circular dependencies. type ConfigProvider interface { ClientConfig(serviceName string, cfgs ...*aws.Config) Config } // A Client implements the base client request and response handling // used by all service clients. type Client struct { request.Retryer metadata.ClientInfo Config aws.Config Handlers request.Handlers } // New will return a pointer to a new initialized service client. func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client { svc := &Client{ Config: cfg, ClientInfo: info, Handlers: handlers, } switch retryer, ok := cfg.Retryer.(request.Retryer); { case ok: svc.Retryer = retryer case cfg.Retryer != nil && cfg.Logger != nil: s := fmt.Sprintf("WARNING: %T does not implement request.Retryer; using DefaultRetryer instead", cfg.Retryer) cfg.Logger.Log(s) fallthrough default: maxRetries := aws.IntValue(cfg.MaxRetries) if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries { maxRetries = 3 } svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries} } svc.AddDebugHandlers() for _, option := range options { option(svc) } return svc } // NewRequest returns a new Request pointer for the service API // operation and parameters. func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request { return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data) } // AddDebugHandlers injects debug logging handlers into the service to log request // debug information. func (c *Client) AddDebugHandlers() { if !c.Config.LogLevel.AtLeast(aws.LogDebug) { return } c.Handlers.Send.PushFront(logRequest) c.Handlers.Send.PushBack(logResponse) } const logReqMsg = `DEBUG: Request %s/%s Details: ---[ REQUEST POST-SIGN ]----------------------------- %s -----------------------------------------------------` const logReqErrMsg = `DEBUG ERROR: Request %s/%s: ---[ REQUEST DUMP ERROR ]----------------------------- %s -----------------------------------------------------` func logRequest(r *request.Request) { logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) dumpedBody, err := httputil.DumpRequestOut(r.HTTPRequest, logBody) if err != nil { r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err)) return } if logBody { // Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's // Body as a NoOpCloser and will not be reset after read by the HTTP // client reader. r.Body.Seek(r.BodyStart, 0) r.HTTPRequest.Body = ioutil.NopCloser(r.Body) } r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody))) } const logRespMsg = `DEBUG: Response %s/%s Details: ---[ RESPONSE ]-------------------------------------- %s -----------------------------------------------------` const logRespErrMsg = `DEBUG ERROR: Response %s/%s: ---[ RESPONSE DUMP ERROR ]----------------------------- %s -----------------------------------------------------` func logResponse(r *request.Request) { var msg = "no response data" if r.HTTPResponse != nil { logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) dumpedBody, err := httputil.DumpResponse(r.HTTPResponse, logBody) if err != nil { r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err)) return } msg = string(dumpedBody) } else if r.Error != nil { msg = r.Error.Error() } r.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.ClientInfo.ServiceName, r.Operation.Name, msg)) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go ================================================ package client import ( "math/rand" "sync" "time" "github.com/aws/aws-sdk-go/aws/request" ) // DefaultRetryer implements basic retry logic using exponential backoff for // most services. If you want to implement custom retry logic, implement the // request.Retryer interface or create a structure type that composes this // struct and override the specific methods. For example, to override only // the MaxRetries method: // // type retryer struct { // service.DefaultRetryer // } // // // This implementation always has 100 max retries // func (d retryer) MaxRetries() uint { return 100 } type DefaultRetryer struct { NumMaxRetries int } // MaxRetries returns the number of maximum returns the service will use to make // an individual API request. func (d DefaultRetryer) MaxRetries() int { return d.NumMaxRetries } var seededRand = rand.New(&lockedSource{src: rand.NewSource(time.Now().UnixNano())}) // RetryRules returns the delay duration before retrying this request again func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration { // Set the upper limit of delay in retrying at ~five minutes minTime := 30 throttle := d.shouldThrottle(r) if throttle { minTime = 500 } retryCount := r.RetryCount if retryCount > 13 { retryCount = 13 } else if throttle && retryCount > 8 { retryCount = 8 } delay := (1 << uint(retryCount)) * (seededRand.Intn(minTime) + minTime) return time.Duration(delay) * time.Millisecond } // ShouldRetry returns true if the request should be retried. func (d DefaultRetryer) ShouldRetry(r *request.Request) bool { if r.HTTPResponse.StatusCode >= 500 { return true } return r.IsErrorRetryable() || d.shouldThrottle(r) } // ShouldThrottle returns true if the request should be throttled. func (d DefaultRetryer) shouldThrottle(r *request.Request) bool { if r.HTTPResponse.StatusCode == 502 || r.HTTPResponse.StatusCode == 503 || r.HTTPResponse.StatusCode == 504 { return true } return r.IsErrorThrottle() } // lockedSource is a thread-safe implementation of rand.Source type lockedSource struct { lk sync.Mutex src rand.Source } func (r *lockedSource) Int63() (n int64) { r.lk.Lock() n = r.src.Int63() r.lk.Unlock() return } func (r *lockedSource) Seed(seed int64) { r.lk.Lock() r.src.Seed(seed) r.lk.Unlock() } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go ================================================ package metadata // ClientInfo wraps immutable data from the client.Client structure. type ClientInfo struct { ServiceName string APIVersion string Endpoint string SigningName string SigningRegion string JSONVersion string TargetPrefix string } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/config.go ================================================ package aws import ( "net/http" "time" "github.com/aws/aws-sdk-go/aws/credentials" ) // UseServiceDefaultRetries instructs the config to use the service's own // default number of retries. This will be the default action if // Config.MaxRetries is nil also. const UseServiceDefaultRetries = -1 // RequestRetryer is an alias for a type that implements the request.Retryer // interface. type RequestRetryer interface{} // A Config provides service configuration for service clients. By default, // all clients will use the defaults.DefaultConfig tructure. // // // Create Session with MaxRetry configuration to be shared by multiple // // service clients. // sess, err := session.NewSession(&aws.Config{ // MaxRetries: aws.Int(3), // }) // // // Create S3 service client with a specific Region. // svc := s3.New(sess, &aws.Config{ // Region: aws.String("us-west-2"), // }) type Config struct { // Enables verbose error printing of all credential chain errors. // Should be used when wanting to see all errors while attempting to // retrieve credentials. CredentialsChainVerboseErrors *bool // The credentials object to use when signing requests. Defaults to a // chain of credential providers to search for credentials in environment // variables, shared credential file, and EC2 Instance Roles. Credentials *credentials.Credentials // An optional endpoint URL (hostname only or fully qualified URI) // that overrides the default generated endpoint for a client. Set this // to `""` to use the default generated endpoint. // // @note You must still provide a `Region` value when specifying an // endpoint for a client. Endpoint *string // The region to send requests to. This parameter is required and must // be configured globally or on a per-client basis unless otherwise // noted. A full list of regions is found in the "Regions and Endpoints" // document. // // @see http://docs.aws.amazon.com/general/latest/gr/rande.html // AWS Regions and Endpoints Region *string // Set this to `true` to disable SSL when sending requests. Defaults // to `false`. DisableSSL *bool // The HTTP client to use when sending requests. Defaults to // `http.DefaultClient`. HTTPClient *http.Client // An integer value representing the logging level. The default log level // is zero (LogOff), which represents no logging. To enable logging set // to a LogLevel Value. LogLevel *LogLevelType // The logger writer interface to write logging messages to. Defaults to // standard out. Logger Logger // The maximum number of times that a request will be retried for failures. // Defaults to -1, which defers the max retry setting to the service // specific configuration. MaxRetries *int // Retryer guides how HTTP requests should be retried in case of // recoverable failures. // // When nil or the value does not implement the request.Retryer interface, // the request.DefaultRetryer will be used. // // When both Retryer and MaxRetries are non-nil, the former is used and // the latter ignored. // // To set the Retryer field in a type-safe manner and with chaining, use // the request.WithRetryer helper function: // // cfg := request.WithRetryer(aws.NewConfig(), myRetryer) // Retryer RequestRetryer // Disables semantic parameter validation, which validates input for // missing required fields and/or other semantic request input errors. DisableParamValidation *bool // Disables the computation of request and response checksums, e.g., // CRC32 checksums in Amazon DynamoDB. DisableComputeChecksums *bool // Set this to `true` to force the request to use path-style addressing, // i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client // will use virtual hosted bucket addressing when possible // (`http://BUCKET.s3.amazonaws.com/KEY`). // // @note This configuration option is specific to the Amazon S3 service. // @see http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html // Amazon S3: Virtual Hosting of Buckets S3ForcePathStyle *bool // Set this to `true` to disable the SDK adding the `Expect: 100-Continue` // header to PUT requests over 2MB of content. 100-Continue instructs the // HTTP client not to send the body until the service responds with a // `continue` status. This is useful to prevent sending the request body // until after the request is authenticated, and validated. // // http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html // // 100-Continue is only enabled for Go 1.6 and above. See `http.Transport`'s // `ExpectContinueTimeout` for information on adjusting the continue wait // timeout. https://golang.org/pkg/net/http/#Transport // // You should use this flag to disble 100-Continue if you experience issues // with proxies or third party S3 compatible services. S3Disable100Continue *bool // Set this to `true` to enable S3 Accelerate feature. For all operations // compatible with S3 Accelerate will use the accelerate endpoint for // requests. Requests not compatible will fall back to normal S3 requests. // // The bucket must be enable for accelerate to be used with S3 client with // accelerate enabled. If the bucket is not enabled for accelerate an error // will be returned. The bucket name must be DNS compatible to also work // with accelerate. // // Not compatible with UseDualStack requests will fail if both flags are // specified. S3UseAccelerate *bool // Set this to `true` to disable the EC2Metadata client from overriding the // default http.Client's Timeout. This is helpful if you do not want the // EC2Metadata client to create a new http.Client. This options is only // meaningful if you're not already using a custom HTTP client with the // SDK. Enabled by default. // // Must be set and provided to the session.NewSession() in order to disable // the EC2Metadata overriding the timeout for default credentials chain. // // Example: // sess, err := session.NewSession(aws.NewConfig().WithEC2MetadataDiableTimeoutOverride(true)) // // svc := s3.New(sess) // EC2MetadataDisableTimeoutOverride *bool // Instructs the endpiont to be generated for a service client to // be the dual stack endpoint. The dual stack endpoint will support // both IPv4 and IPv6 addressing. // // Setting this for a service which does not support dual stack will fail // to make requets. It is not recommended to set this value on the session // as it will apply to all service clients created with the session. Even // services which don't support dual stack endpoints. // // If the Endpoint config value is also provided the UseDualStack flag // will be ignored. // // Only supported with. // // sess, err := session.NewSession() // // svc := s3.New(sess, &aws.Config{ // UseDualStack: aws.Bool(true), // }) UseDualStack *bool // SleepDelay is an override for the func the SDK will call when sleeping // during the lifecycle of a request. Specifically this will be used for // request delays. This value should only be used for testing. To adjust // the delay of a request see the aws/client.DefaultRetryer and // aws/request.Retryer. SleepDelay func(time.Duration) } // NewConfig returns a new Config pointer that can be chained with builder // methods to set multiple configuration values inline without using pointers. // // // Create Session with MaxRetry configuration to be shared by multiple // // service clients. // sess, err := session.NewSession(aws.NewConfig(). // WithMaxRetries(3), // ) // // // Create S3 service client with a specific Region. // svc := s3.New(sess, aws.NewConfig(). // WithRegion("us-west-2"), // ) func NewConfig() *Config { return &Config{} } // WithCredentialsChainVerboseErrors sets a config verbose errors boolean and returning // a Config pointer. func (c *Config) WithCredentialsChainVerboseErrors(verboseErrs bool) *Config { c.CredentialsChainVerboseErrors = &verboseErrs return c } // WithCredentials sets a config Credentials value returning a Config pointer // for chaining. func (c *Config) WithCredentials(creds *credentials.Credentials) *Config { c.Credentials = creds return c } // WithEndpoint sets a config Endpoint value returning a Config pointer for // chaining. func (c *Config) WithEndpoint(endpoint string) *Config { c.Endpoint = &endpoint return c } // WithRegion sets a config Region value returning a Config pointer for // chaining. func (c *Config) WithRegion(region string) *Config { c.Region = ®ion return c } // WithDisableSSL sets a config DisableSSL value returning a Config pointer // for chaining. func (c *Config) WithDisableSSL(disable bool) *Config { c.DisableSSL = &disable return c } // WithHTTPClient sets a config HTTPClient value returning a Config pointer // for chaining. func (c *Config) WithHTTPClient(client *http.Client) *Config { c.HTTPClient = client return c } // WithMaxRetries sets a config MaxRetries value returning a Config pointer // for chaining. func (c *Config) WithMaxRetries(max int) *Config { c.MaxRetries = &max return c } // WithDisableParamValidation sets a config DisableParamValidation value // returning a Config pointer for chaining. func (c *Config) WithDisableParamValidation(disable bool) *Config { c.DisableParamValidation = &disable return c } // WithDisableComputeChecksums sets a config DisableComputeChecksums value // returning a Config pointer for chaining. func (c *Config) WithDisableComputeChecksums(disable bool) *Config { c.DisableComputeChecksums = &disable return c } // WithLogLevel sets a config LogLevel value returning a Config pointer for // chaining. func (c *Config) WithLogLevel(level LogLevelType) *Config { c.LogLevel = &level return c } // WithLogger sets a config Logger value returning a Config pointer for // chaining. func (c *Config) WithLogger(logger Logger) *Config { c.Logger = logger return c } // WithS3ForcePathStyle sets a config S3ForcePathStyle value returning a Config // pointer for chaining. func (c *Config) WithS3ForcePathStyle(force bool) *Config { c.S3ForcePathStyle = &force return c } // WithS3Disable100Continue sets a config S3Disable100Continue value returning // a Config pointer for chaining. func (c *Config) WithS3Disable100Continue(disable bool) *Config { c.S3Disable100Continue = &disable return c } // WithS3UseAccelerate sets a config S3UseAccelerate value returning a Config // pointer for chaining. func (c *Config) WithS3UseAccelerate(enable bool) *Config { c.S3UseAccelerate = &enable return c } // WithUseDualStack sets a config UseDualStack value returning a Config // pointer for chaining. func (c *Config) WithUseDualStack(enable bool) *Config { c.UseDualStack = &enable return c } // WithEC2MetadataDisableTimeoutOverride sets a config EC2MetadataDisableTimeoutOverride value // returning a Config pointer for chaining. func (c *Config) WithEC2MetadataDisableTimeoutOverride(enable bool) *Config { c.EC2MetadataDisableTimeoutOverride = &enable return c } // WithSleepDelay overrides the function used to sleep while waiting for the // next retry. Defaults to time.Sleep. func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config { c.SleepDelay = fn return c } // MergeIn merges the passed in configs into the existing config object. func (c *Config) MergeIn(cfgs ...*Config) { for _, other := range cfgs { mergeInConfig(c, other) } } func mergeInConfig(dst *Config, other *Config) { if other == nil { return } if other.CredentialsChainVerboseErrors != nil { dst.CredentialsChainVerboseErrors = other.CredentialsChainVerboseErrors } if other.Credentials != nil { dst.Credentials = other.Credentials } if other.Endpoint != nil { dst.Endpoint = other.Endpoint } if other.Region != nil { dst.Region = other.Region } if other.DisableSSL != nil { dst.DisableSSL = other.DisableSSL } if other.HTTPClient != nil { dst.HTTPClient = other.HTTPClient } if other.LogLevel != nil { dst.LogLevel = other.LogLevel } if other.Logger != nil { dst.Logger = other.Logger } if other.MaxRetries != nil { dst.MaxRetries = other.MaxRetries } if other.Retryer != nil { dst.Retryer = other.Retryer } if other.DisableParamValidation != nil { dst.DisableParamValidation = other.DisableParamValidation } if other.DisableComputeChecksums != nil { dst.DisableComputeChecksums = other.DisableComputeChecksums } if other.S3ForcePathStyle != nil { dst.S3ForcePathStyle = other.S3ForcePathStyle } if other.S3Disable100Continue != nil { dst.S3Disable100Continue = other.S3Disable100Continue } if other.S3UseAccelerate != nil { dst.S3UseAccelerate = other.S3UseAccelerate } if other.UseDualStack != nil { dst.UseDualStack = other.UseDualStack } if other.EC2MetadataDisableTimeoutOverride != nil { dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride } if other.SleepDelay != nil { dst.SleepDelay = other.SleepDelay } } // Copy will return a shallow copy of the Config object. If any additional // configurations are provided they will be merged into the new config returned. func (c *Config) Copy(cfgs ...*Config) *Config { dst := &Config{} dst.MergeIn(c) for _, cfg := range cfgs { dst.MergeIn(cfg) } return dst } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/convert_types.go ================================================ package aws import "time" // String returns a pointer to the string value passed in. func String(v string) *string { return &v } // StringValue returns the value of the string pointer passed in or // "" if the pointer is nil. func StringValue(v *string) string { if v != nil { return *v } return "" } // StringSlice converts a slice of string values into a slice of // string pointers func StringSlice(src []string) []*string { dst := make([]*string, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // StringValueSlice converts a slice of string pointers into a slice of // string values func StringValueSlice(src []*string) []string { dst := make([]string, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // StringMap converts a string map of string values into a string // map of string pointers func StringMap(src map[string]string) map[string]*string { dst := make(map[string]*string) for k, val := range src { v := val dst[k] = &v } return dst } // StringValueMap converts a string map of string pointers into a string // map of string values func StringValueMap(src map[string]*string) map[string]string { dst := make(map[string]string) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Bool returns a pointer to the bool value passed in. func Bool(v bool) *bool { return &v } // BoolValue returns the value of the bool pointer passed in or // false if the pointer is nil. func BoolValue(v *bool) bool { if v != nil { return *v } return false } // BoolSlice converts a slice of bool values into a slice of // bool pointers func BoolSlice(src []bool) []*bool { dst := make([]*bool, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // BoolValueSlice converts a slice of bool pointers into a slice of // bool values func BoolValueSlice(src []*bool) []bool { dst := make([]bool, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // BoolMap converts a string map of bool values into a string // map of bool pointers func BoolMap(src map[string]bool) map[string]*bool { dst := make(map[string]*bool) for k, val := range src { v := val dst[k] = &v } return dst } // BoolValueMap converts a string map of bool pointers into a string // map of bool values func BoolValueMap(src map[string]*bool) map[string]bool { dst := make(map[string]bool) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Int returns a pointer to the int value passed in. func Int(v int) *int { return &v } // IntValue returns the value of the int pointer passed in or // 0 if the pointer is nil. func IntValue(v *int) int { if v != nil { return *v } return 0 } // IntSlice converts a slice of int values into a slice of // int pointers func IntSlice(src []int) []*int { dst := make([]*int, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // IntValueSlice converts a slice of int pointers into a slice of // int values func IntValueSlice(src []*int) []int { dst := make([]int, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // IntMap converts a string map of int values into a string // map of int pointers func IntMap(src map[string]int) map[string]*int { dst := make(map[string]*int) for k, val := range src { v := val dst[k] = &v } return dst } // IntValueMap converts a string map of int pointers into a string // map of int values func IntValueMap(src map[string]*int) map[string]int { dst := make(map[string]int) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Int64 returns a pointer to the int64 value passed in. func Int64(v int64) *int64 { return &v } // Int64Value returns the value of the int64 pointer passed in or // 0 if the pointer is nil. func Int64Value(v *int64) int64 { if v != nil { return *v } return 0 } // Int64Slice converts a slice of int64 values into a slice of // int64 pointers func Int64Slice(src []int64) []*int64 { dst := make([]*int64, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Int64ValueSlice converts a slice of int64 pointers into a slice of // int64 values func Int64ValueSlice(src []*int64) []int64 { dst := make([]int64, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Int64Map converts a string map of int64 values into a string // map of int64 pointers func Int64Map(src map[string]int64) map[string]*int64 { dst := make(map[string]*int64) for k, val := range src { v := val dst[k] = &v } return dst } // Int64ValueMap converts a string map of int64 pointers into a string // map of int64 values func Int64ValueMap(src map[string]*int64) map[string]int64 { dst := make(map[string]int64) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Float64 returns a pointer to the float64 value passed in. func Float64(v float64) *float64 { return &v } // Float64Value returns the value of the float64 pointer passed in or // 0 if the pointer is nil. func Float64Value(v *float64) float64 { if v != nil { return *v } return 0 } // Float64Slice converts a slice of float64 values into a slice of // float64 pointers func Float64Slice(src []float64) []*float64 { dst := make([]*float64, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Float64ValueSlice converts a slice of float64 pointers into a slice of // float64 values func Float64ValueSlice(src []*float64) []float64 { dst := make([]float64, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Float64Map converts a string map of float64 values into a string // map of float64 pointers func Float64Map(src map[string]float64) map[string]*float64 { dst := make(map[string]*float64) for k, val := range src { v := val dst[k] = &v } return dst } // Float64ValueMap converts a string map of float64 pointers into a string // map of float64 values func Float64ValueMap(src map[string]*float64) map[string]float64 { dst := make(map[string]float64) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Time returns a pointer to the time.Time value passed in. func Time(v time.Time) *time.Time { return &v } // TimeValue returns the value of the time.Time pointer passed in or // time.Time{} if the pointer is nil. func TimeValue(v *time.Time) time.Time { if v != nil { return *v } return time.Time{} } // TimeUnixMilli returns a Unix timestamp in milliseconds from "January 1, 1970 UTC". // The result is undefined if the Unix time cannot be represented by an int64. // Which includes calling TimeUnixMilli on a zero Time is undefined. // // This utility is useful for service API's such as CloudWatch Logs which require // their unix time values to be in milliseconds. // // See Go stdlib https://golang.org/pkg/time/#Time.UnixNano for more information. func TimeUnixMilli(t time.Time) int64 { return t.UnixNano() / int64(time.Millisecond/time.Nanosecond) } // TimeSlice converts a slice of time.Time values into a slice of // time.Time pointers func TimeSlice(src []time.Time) []*time.Time { dst := make([]*time.Time, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // TimeValueSlice converts a slice of time.Time pointers into a slice of // time.Time values func TimeValueSlice(src []*time.Time) []time.Time { dst := make([]time.Time, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // TimeMap converts a string map of time.Time values into a string // map of time.Time pointers func TimeMap(src map[string]time.Time) map[string]*time.Time { dst := make(map[string]*time.Time) for k, val := range src { v := val dst[k] = &v } return dst } // TimeValueMap converts a string map of time.Time pointers into a string // map of time.Time values func TimeValueMap(src map[string]*time.Time) map[string]time.Time { dst := make(map[string]time.Time) for k, val := range src { if val != nil { dst[k] = *val } } return dst } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go ================================================ package corehandlers import ( "bytes" "fmt" "io" "io/ioutil" "net/http" "net/url" "regexp" "runtime" "strconv" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" ) // Interface for matching types which also have a Len method. type lener interface { Len() int } // BuildContentLengthHandler builds the content length of a request based on the body, // or will use the HTTPRequest.Header's "Content-Length" if defined. If unable // to determine request body length and no "Content-Length" was specified it will panic. // // The Content-Length will only be aded to the request if the length of the body // is greater than 0. If the body is empty or the current `Content-Length` // header is <= 0, the header will also be stripped. var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLengthHandler", Fn: func(r *request.Request) { var length int64 if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" { length, _ = strconv.ParseInt(slength, 10, 64) } else { switch body := r.Body.(type) { case nil: length = 0 case lener: length = int64(body.Len()) case io.Seeker: r.BodyStart, _ = body.Seek(0, 1) end, _ := body.Seek(0, 2) body.Seek(r.BodyStart, 0) // make sure to seek back to original location length = end - r.BodyStart default: panic("Cannot get length of body, must provide `ContentLength`") } } if length > 0 { r.HTTPRequest.ContentLength = length r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length)) } else { r.HTTPRequest.ContentLength = 0 r.HTTPRequest.Header.Del("Content-Length") } }} // SDKVersionUserAgentHandler is a request handler for adding the SDK Version to the user agent. var SDKVersionUserAgentHandler = request.NamedHandler{ Name: "core.SDKVersionUserAgentHandler", Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH), } var reStatusCode = regexp.MustCompile(`^(\d{3})`) // SendHandler is a request handler to send service request using HTTP client. var SendHandler = request.NamedHandler{Name: "core.SendHandler", Fn: func(r *request.Request) { var err error r.HTTPResponse, err = r.Config.HTTPClient.Do(r.HTTPRequest) if err != nil { // Prevent leaking if an HTTPResponse was returned. Clean up // the body. if r.HTTPResponse != nil { r.HTTPResponse.Body.Close() } // Capture the case where url.Error is returned for error processing // response. e.g. 301 without location header comes back as string // error and r.HTTPResponse is nil. Other url redirect errors will // comeback in a similar method. if e, ok := err.(*url.Error); ok && e.Err != nil { if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil { code, _ := strconv.ParseInt(s[1], 10, 64) r.HTTPResponse = &http.Response{ StatusCode: int(code), Status: http.StatusText(int(code)), Body: ioutil.NopCloser(bytes.NewReader([]byte{})), } return } } if r.HTTPResponse == nil { // Add a dummy request response object to ensure the HTTPResponse // value is consistent. r.HTTPResponse = &http.Response{ StatusCode: int(0), Status: http.StatusText(int(0)), Body: ioutil.NopCloser(bytes.NewReader([]byte{})), } } // Catch all other request errors. r.Error = awserr.New("RequestError", "send request failed", err) r.Retryable = aws.Bool(true) // network errors are retryable } }} // ValidateResponseHandler is a request handler to validate service response. var ValidateResponseHandler = request.NamedHandler{Name: "core.ValidateResponseHandler", Fn: func(r *request.Request) { if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 { // this may be replaced by an UnmarshalError handler r.Error = awserr.New("UnknownError", "unknown error", nil) } }} // AfterRetryHandler performs final checks to determine if the request should // be retried and how long to delay. var AfterRetryHandler = request.NamedHandler{Name: "core.AfterRetryHandler", Fn: func(r *request.Request) { // If one of the other handlers already set the retry state // we don't want to override it based on the service's state if r.Retryable == nil { r.Retryable = aws.Bool(r.ShouldRetry(r)) } if r.WillRetry() { r.RetryDelay = r.RetryRules(r) r.Config.SleepDelay(r.RetryDelay) // when the expired token exception occurs the credentials // need to be expired locally so that the next request to // get credentials will trigger a credentials refresh. if r.IsErrorExpired() { r.Config.Credentials.Expire() } r.RetryCount++ r.Error = nil } }} // ValidateEndpointHandler is a request handler to validate a request had the // appropriate Region and Endpoint set. Will set r.Error if the endpoint or // region is not valid. var ValidateEndpointHandler = request.NamedHandler{Name: "core.ValidateEndpointHandler", Fn: func(r *request.Request) { if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" { r.Error = aws.ErrMissingRegion } else if r.ClientInfo.Endpoint == "" { r.Error = aws.ErrMissingEndpoint } }} ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go ================================================ package corehandlers import "github.com/aws/aws-sdk-go/aws/request" // ValidateParametersHandler is a request handler to validate the input parameters. // Validating parameters only has meaning if done prior to the request being sent. var ValidateParametersHandler = request.NamedHandler{Name: "core.ValidateParametersHandler", Fn: func(r *request.Request) { if !r.ParamsFilled() { return } if v, ok := r.Params.(request.Validator); ok { if err := v.Validate(); err != nil { r.Error = err } } }} ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go ================================================ package credentials import ( "github.com/aws/aws-sdk-go/aws/awserr" ) var ( // ErrNoValidProvidersFoundInChain Is returned when there are no valid // providers in the ChainProvider. // // This has been deprecated. For verbose error messaging set // aws.Config.CredentialsChainVerboseErrors to true // // @readonly ErrNoValidProvidersFoundInChain = awserr.New("NoCredentialProviders", `no valid providers in chain. Deprecated. For verbose messaging see aws.Config.CredentialsChainVerboseErrors`, nil) ) // A ChainProvider will search for a provider which returns credentials // and cache that provider until Retrieve is called again. // // The ChainProvider provides a way of chaining multiple providers together // which will pick the first available using priority order of the Providers // in the list. // // If none of the Providers retrieve valid credentials Value, ChainProvider's // Retrieve() will return the error ErrNoValidProvidersFoundInChain. // // If a Provider is found which returns valid credentials Value ChainProvider // will cache that Provider for all calls to IsExpired(), until Retrieve is // called again. // // Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider. // In this example EnvProvider will first check if any credentials are available // vai the environment variables. If there are none ChainProvider will check // the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider // does not return any credentials ChainProvider will return the error // ErrNoValidProvidersFoundInChain // // creds := NewChainCredentials( // []Provider{ // &EnvProvider{}, // &EC2RoleProvider{ // Client: ec2metadata.New(sess), // }, // }) // // // Usage of ChainCredentials with aws.Config // svc := ec2.New(&aws.Config{Credentials: creds}) // type ChainProvider struct { Providers []Provider curr Provider VerboseErrors bool } // NewChainCredentials returns a pointer to a new Credentials object // wrapping a chain of providers. func NewChainCredentials(providers []Provider) *Credentials { return NewCredentials(&ChainProvider{ Providers: append([]Provider{}, providers...), }) } // Retrieve returns the credentials value or error if no provider returned // without error. // // If a provider is found it will be cached and any calls to IsExpired() // will return the expired state of the cached provider. func (c *ChainProvider) Retrieve() (Value, error) { var errs []error for _, p := range c.Providers { creds, err := p.Retrieve() if err == nil { c.curr = p return creds, nil } errs = append(errs, err) } c.curr = nil var err error err = ErrNoValidProvidersFoundInChain if c.VerboseErrors { err = awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs) } return Value{}, err } // IsExpired will returned the expired state of the currently cached provider // if there is one. If there is no current provider, true will be returned. func (c *ChainProvider) IsExpired() bool { if c.curr != nil { return c.curr.IsExpired() } return true } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go ================================================ // Package credentials provides credential retrieval and management // // The Credentials is the primary method of getting access to and managing // credentials Values. Using dependency injection retrieval of the credential // values is handled by a object which satisfies the Provider interface. // // By default the Credentials.Get() will cache the successful result of a // Provider's Retrieve() until Provider.IsExpired() returns true. At which // point Credentials will call Provider's Retrieve() to get new credential Value. // // The Provider is responsible for determining when credentials Value have expired. // It is also important to note that Credentials will always call Retrieve the // first time Credentials.Get() is called. // // Example of using the environment variable credentials. // // creds := NewEnvCredentials() // // // Retrieve the credentials value // credValue, err := creds.Get() // if err != nil { // // handle error // } // // Example of forcing credentials to expire and be refreshed on the next Get(). // This may be helpful to proactively expire credentials and refresh them sooner // than they would naturally expire on their own. // // creds := NewCredentials(&EC2RoleProvider{}) // creds.Expire() // credsValue, err := creds.Get() // // New credentials will be retrieved instead of from cache. // // // Custom Provider // // Each Provider built into this package also provides a helper method to generate // a Credentials pointer setup with the provider. To use a custom Provider just // create a type which satisfies the Provider interface and pass it to the // NewCredentials method. // // type MyProvider struct{} // func (m *MyProvider) Retrieve() (Value, error) {...} // func (m *MyProvider) IsExpired() bool {...} // // creds := NewCredentials(&MyProvider{}) // credValue, err := creds.Get() // package credentials import ( "sync" "time" ) // AnonymousCredentials is an empty Credential object that can be used as // dummy placeholder credentials for requests that do not need signed. // // This Credentials can be used to configure a service to not sign requests // when making service API calls. For example, when accessing public // s3 buckets. // // svc := s3.New(&aws.Config{Credentials: AnonymousCredentials}) // // Access public S3 buckets. // // @readonly var AnonymousCredentials = NewStaticCredentials("", "", "") // A Value is the AWS credentials value for individual credential fields. type Value struct { // AWS Access key ID AccessKeyID string // AWS Secret Access Key SecretAccessKey string // AWS Session Token SessionToken string // Provider used to get credentials ProviderName string } // A Provider is the interface for any component which will provide credentials // Value. A provider is required to manage its own Expired state, and what to // be expired means. // // The Provider should not need to implement its own mutexes, because // that will be managed by Credentials. type Provider interface { // Refresh returns nil if it successfully retrieved the value. // Error is returned if the value were not obtainable, or empty. Retrieve() (Value, error) // IsExpired returns if the credentials are no longer valid, and need // to be retrieved. IsExpired() bool } // A Expiry provides shared expiration logic to be used by credentials // providers to implement expiry functionality. // // The best method to use this struct is as an anonymous field within the // provider's struct. // // Example: // type EC2RoleProvider struct { // Expiry // ... // } type Expiry struct { // The date/time when to expire on expiration time.Time // If set will be used by IsExpired to determine the current time. // Defaults to time.Now if CurrentTime is not set. Available for testing // to be able to mock out the current time. CurrentTime func() time.Time } // SetExpiration sets the expiration IsExpired will check when called. // // If window is greater than 0 the expiration time will be reduced by the // window value. // // Using a window is helpful to trigger credentials to expire sooner than // the expiration time given to ensure no requests are made with expired // tokens. func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) { e.expiration = expiration if window > 0 { e.expiration = e.expiration.Add(-window) } } // IsExpired returns if the credentials are expired. func (e *Expiry) IsExpired() bool { if e.CurrentTime == nil { e.CurrentTime = time.Now } return e.expiration.Before(e.CurrentTime()) } // A Credentials provides synchronous safe retrieval of AWS credentials Value. // Credentials will cache the credentials value until they expire. Once the value // expires the next Get will attempt to retrieve valid credentials. // // Credentials is safe to use across multiple goroutines and will manage the // synchronous state so the Providers do not need to implement their own // synchronization. // // The first Credentials.Get() will always call Provider.Retrieve() to get the // first instance of the credentials Value. All calls to Get() after that // will return the cached credentials Value until IsExpired() returns true. type Credentials struct { creds Value forceRefresh bool m sync.Mutex provider Provider } // NewCredentials returns a pointer to a new Credentials with the provider set. func NewCredentials(provider Provider) *Credentials { return &Credentials{ provider: provider, forceRefresh: true, } } // Get returns the credentials value, or error if the credentials Value failed // to be retrieved. // // Will return the cached credentials Value if it has not expired. If the // credentials Value has expired the Provider's Retrieve() will be called // to refresh the credentials. // // If Credentials.Expire() was called the credentials Value will be force // expired, and the next call to Get() will cause them to be refreshed. func (c *Credentials) Get() (Value, error) { c.m.Lock() defer c.m.Unlock() if c.isExpired() { creds, err := c.provider.Retrieve() if err != nil { return Value{}, err } c.creds = creds c.forceRefresh = false } return c.creds, nil } // Expire expires the credentials and forces them to be retrieved on the // next call to Get(). // // This will override the Provider's expired state, and force Credentials // to call the Provider's Retrieve(). func (c *Credentials) Expire() { c.m.Lock() defer c.m.Unlock() c.forceRefresh = true } // IsExpired returns if the credentials are no longer valid, and need // to be retrieved. // // If the Credentials were forced to be expired with Expire() this will // reflect that override. func (c *Credentials) IsExpired() bool { c.m.Lock() defer c.m.Unlock() return c.isExpired() } // isExpired helper method wrapping the definition of expired credentials. func (c *Credentials) isExpired() bool { return c.forceRefresh || c.provider.IsExpired() } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go ================================================ package ec2rolecreds import ( "bufio" "encoding/json" "fmt" "path" "strings" "time" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/ec2metadata" ) // ProviderName provides a name of EC2Role provider const ProviderName = "EC2RoleProvider" // A EC2RoleProvider retrieves credentials from the EC2 service, and keeps track if // those credentials are expired. // // Example how to configure the EC2RoleProvider with custom http Client, Endpoint // or ExpiryWindow // // p := &ec2rolecreds.EC2RoleProvider{ // // Pass in a custom timeout to be used when requesting // // IAM EC2 Role credentials. // Client: ec2metadata.New(sess, aws.Config{ // HTTPClient: &http.Client{Timeout: 10 * time.Second}, // }), // // // Do not use early expiry of credentials. If a non zero value is // // specified the credentials will be expired early // ExpiryWindow: 0, // } type EC2RoleProvider struct { credentials.Expiry // Required EC2Metadata client to use when connecting to EC2 metadata service. Client *ec2metadata.EC2Metadata // ExpiryWindow will allow the credentials to trigger refreshing prior to // the credentials actually expiring. This is beneficial so race conditions // with expiring credentials do not cause request to fail unexpectedly // due to ExpiredTokenException exceptions. // // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true // 10 seconds before the credentials are actually expired. // // If ExpiryWindow is 0 or less it will be ignored. ExpiryWindow time.Duration } // NewCredentials returns a pointer to a new Credentials object wrapping // the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client. // The ConfigProvider is satisfied by the session.Session type. func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials { p := &EC2RoleProvider{ Client: ec2metadata.New(c), } for _, option := range options { option(p) } return credentials.NewCredentials(p) } // NewCredentialsWithClient returns a pointer to a new Credentials object wrapping // the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2 // metadata service. func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials { p := &EC2RoleProvider{ Client: client, } for _, option := range options { option(p) } return credentials.NewCredentials(p) } // Retrieve retrieves credentials from the EC2 service. // Error will be returned if the request fails, or unable to extract // the desired credentials. func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) { credsList, err := requestCredList(m.Client) if err != nil { return credentials.Value{ProviderName: ProviderName}, err } if len(credsList) == 0 { return credentials.Value{ProviderName: ProviderName}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil) } credsName := credsList[0] roleCreds, err := requestCred(m.Client, credsName) if err != nil { return credentials.Value{ProviderName: ProviderName}, err } m.SetExpiration(roleCreds.Expiration, m.ExpiryWindow) return credentials.Value{ AccessKeyID: roleCreds.AccessKeyID, SecretAccessKey: roleCreds.SecretAccessKey, SessionToken: roleCreds.Token, ProviderName: ProviderName, }, nil } // A ec2RoleCredRespBody provides the shape for unmarshalling credential // request responses. type ec2RoleCredRespBody struct { // Success State Expiration time.Time AccessKeyID string SecretAccessKey string Token string // Error state Code string Message string } const iamSecurityCredsPath = "/iam/security-credentials" // requestCredList requests a list of credentials from the EC2 service. // If there are no credentials, or there is an error making or receiving the request func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) { resp, err := client.GetMetadata(iamSecurityCredsPath) if err != nil { return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err) } credsList := []string{} s := bufio.NewScanner(strings.NewReader(resp)) for s.Scan() { credsList = append(credsList, s.Text()) } if err := s.Err(); err != nil { return nil, awserr.New("SerializationError", "failed to read EC2 instance role from metadata service", err) } return credsList, nil } // requestCred requests the credentials for a specific credentials from the EC2 service. // // If the credentials cannot be found, or there is an error reading the response // and error will be returned. func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) { resp, err := client.GetMetadata(path.Join(iamSecurityCredsPath, credsName)) if err != nil { return ec2RoleCredRespBody{}, awserr.New("EC2RoleRequestError", fmt.Sprintf("failed to get %s EC2 instance role credentials", credsName), err) } respCreds := ec2RoleCredRespBody{} if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil { return ec2RoleCredRespBody{}, awserr.New("SerializationError", fmt.Sprintf("failed to decode %s EC2 instance role credentials", credsName), err) } if respCreds.Code != "Success" { // If an error code was returned something failed requesting the role. return ec2RoleCredRespBody{}, awserr.New(respCreds.Code, respCreds.Message, nil) } return respCreds, nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go ================================================ // Package endpointcreds provides support for retrieving credentials from an // arbitrary HTTP endpoint. // // The credentials endpoint Provider can receive both static and refreshable // credentials that will expire. Credentials are static when an "Expiration" // value is not provided in the endpoint's response. // // Static credentials will never expire once they have been retrieved. The format // of the static credentials response: // { // "AccessKeyId" : "MUA...", // "SecretAccessKey" : "/7PC5om....", // } // // Refreshable credentials will expire within the "ExpiryWindow" of the Expiration // value in the response. The format of the refreshable credentials response: // { // "AccessKeyId" : "MUA...", // "SecretAccessKey" : "/7PC5om....", // "Token" : "AQoDY....=", // "Expiration" : "2016-02-25T06:03:31Z" // } // // Errors should be returned in the following format and only returned with 400 // or 500 HTTP status codes. // { // "code": "ErrorCode", // "message": "Helpful error message." // } package endpointcreds import ( "encoding/json" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/client/metadata" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/request" ) // ProviderName is the name of the credentials provider. const ProviderName = `CredentialsEndpointProvider` // Provider satisfies the credentials.Provider interface, and is a client to // retrieve credentials from an arbitrary endpoint. type Provider struct { staticCreds bool credentials.Expiry // Requires a AWS Client to make HTTP requests to the endpoint with. // the Endpoint the request will be made to is provided by the aws.Config's // Endpoint value. Client *client.Client // ExpiryWindow will allow the credentials to trigger refreshing prior to // the credentials actually expiring. This is beneficial so race conditions // with expiring credentials do not cause request to fail unexpectedly // due to ExpiredTokenException exceptions. // // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true // 10 seconds before the credentials are actually expired. // // If ExpiryWindow is 0 or less it will be ignored. ExpiryWindow time.Duration } // NewProviderClient returns a credentials Provider for retrieving AWS credentials // from arbitrary endpoint. func NewProviderClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) credentials.Provider { p := &Provider{ Client: client.New( cfg, metadata.ClientInfo{ ServiceName: "CredentialsEndpoint", Endpoint: endpoint, }, handlers, ), } p.Client.Handlers.Unmarshal.PushBack(unmarshalHandler) p.Client.Handlers.UnmarshalError.PushBack(unmarshalError) p.Client.Handlers.Validate.Clear() p.Client.Handlers.Validate.PushBack(validateEndpointHandler) for _, option := range options { option(p) } return p } // NewCredentialsClient returns a Credentials wrapper for retrieving credentials // from an arbitrary endpoint concurrently. The client will request the func NewCredentialsClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) *credentials.Credentials { return credentials.NewCredentials(NewProviderClient(cfg, handlers, endpoint, options...)) } // IsExpired returns true if the credentials retrieved are expired, or not yet // retrieved. func (p *Provider) IsExpired() bool { if p.staticCreds { return false } return p.Expiry.IsExpired() } // Retrieve will attempt to request the credentials from the endpoint the Provider // was configured for. And error will be returned if the retrieval fails. func (p *Provider) Retrieve() (credentials.Value, error) { resp, err := p.getCredentials() if err != nil { return credentials.Value{ProviderName: ProviderName}, awserr.New("CredentialsEndpointError", "failed to load credentials", err) } if resp.Expiration != nil { p.SetExpiration(*resp.Expiration, p.ExpiryWindow) } else { p.staticCreds = true } return credentials.Value{ AccessKeyID: resp.AccessKeyID, SecretAccessKey: resp.SecretAccessKey, SessionToken: resp.Token, ProviderName: ProviderName, }, nil } type getCredentialsOutput struct { Expiration *time.Time AccessKeyID string SecretAccessKey string Token string } type errorOutput struct { Code string `json:"code"` Message string `json:"message"` } func (p *Provider) getCredentials() (*getCredentialsOutput, error) { op := &request.Operation{ Name: "GetCredentials", HTTPMethod: "GET", } out := &getCredentialsOutput{} req := p.Client.NewRequest(op, nil, out) req.HTTPRequest.Header.Set("Accept", "application/json") return out, req.Send() } func validateEndpointHandler(r *request.Request) { if len(r.ClientInfo.Endpoint) == 0 { r.Error = aws.ErrMissingEndpoint } } func unmarshalHandler(r *request.Request) { defer r.HTTPResponse.Body.Close() out := r.Data.(*getCredentialsOutput) if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil { r.Error = awserr.New("SerializationError", "failed to decode endpoint credentials", err, ) } } func unmarshalError(r *request.Request) { defer r.HTTPResponse.Body.Close() var errOut errorOutput if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&errOut); err != nil { r.Error = awserr.New("SerializationError", "failed to decode endpoint credentials", err, ) } // Response body format is not consistent between metadata endpoints. // Grab the error message as a string and include that as the source error r.Error = awserr.New(errOut.Code, errOut.Message, nil) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go ================================================ package credentials import ( "os" "github.com/aws/aws-sdk-go/aws/awserr" ) // EnvProviderName provides a name of Env provider const EnvProviderName = "EnvProvider" var ( // ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be // found in the process's environment. // // @readonly ErrAccessKeyIDNotFound = awserr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil) // ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key // can't be found in the process's environment. // // @readonly ErrSecretAccessKeyNotFound = awserr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil) ) // A EnvProvider retrieves credentials from the environment variables of the // running process. Environment credentials never expire. // // Environment variables used: // // * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY // * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY type EnvProvider struct { retrieved bool } // NewEnvCredentials returns a pointer to a new Credentials object // wrapping the environment variable provider. func NewEnvCredentials() *Credentials { return NewCredentials(&EnvProvider{}) } // Retrieve retrieves the keys from the environment. func (e *EnvProvider) Retrieve() (Value, error) { e.retrieved = false id := os.Getenv("AWS_ACCESS_KEY_ID") if id == "" { id = os.Getenv("AWS_ACCESS_KEY") } secret := os.Getenv("AWS_SECRET_ACCESS_KEY") if secret == "" { secret = os.Getenv("AWS_SECRET_KEY") } if id == "" { return Value{ProviderName: EnvProviderName}, ErrAccessKeyIDNotFound } if secret == "" { return Value{ProviderName: EnvProviderName}, ErrSecretAccessKeyNotFound } e.retrieved = true return Value{ AccessKeyID: id, SecretAccessKey: secret, SessionToken: os.Getenv("AWS_SESSION_TOKEN"), ProviderName: EnvProviderName, }, nil } // IsExpired returns if the credentials have been retrieved. func (e *EnvProvider) IsExpired() bool { return !e.retrieved } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini ================================================ [default] aws_access_key_id = accessKey aws_secret_access_key = secret aws_session_token = token [no_token] aws_access_key_id = accessKey aws_secret_access_key = secret [with_colon] aws_access_key_id: accessKey aws_secret_access_key: secret ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go ================================================ package credentials import ( "fmt" "os" "path/filepath" "github.com/go-ini/ini" "github.com/aws/aws-sdk-go/aws/awserr" ) // SharedCredsProviderName provides a name of SharedCreds provider const SharedCredsProviderName = "SharedCredentialsProvider" var ( // ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found. // // @readonly ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil) ) // A SharedCredentialsProvider retrieves credentials from the current user's home // directory, and keeps track if those credentials are expired. // // Profile ini file example: $HOME/.aws/credentials type SharedCredentialsProvider struct { // Path to the shared credentials file. // // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the // env value is empty will default to current user's home directory. // Linux/OSX: "$HOME/.aws/credentials" // Windows: "%USERPROFILE%\.aws\credentials" Filename string // AWS Profile to extract credentials from the shared credentials file. If empty // will default to environment variable "AWS_PROFILE" or "default" if // environment variable is also not set. Profile string // retrieved states if the credentials have been successfully retrieved. retrieved bool } // NewSharedCredentials returns a pointer to a new Credentials object // wrapping the Profile file provider. func NewSharedCredentials(filename, profile string) *Credentials { return NewCredentials(&SharedCredentialsProvider{ Filename: filename, Profile: profile, }) } // Retrieve reads and extracts the shared credentials from the current // users home directory. func (p *SharedCredentialsProvider) Retrieve() (Value, error) { p.retrieved = false filename, err := p.filename() if err != nil { return Value{ProviderName: SharedCredsProviderName}, err } creds, err := loadProfile(filename, p.profile()) if err != nil { return Value{ProviderName: SharedCredsProviderName}, err } p.retrieved = true return creds, nil } // IsExpired returns if the shared credentials have expired. func (p *SharedCredentialsProvider) IsExpired() bool { return !p.retrieved } // loadProfiles loads from the file pointed to by shared credentials filename for profile. // The credentials retrieved from the profile will be returned or error. Error will be // returned if it fails to read from the file, or the data is invalid. func loadProfile(filename, profile string) (Value, error) { config, err := ini.Load(filename) if err != nil { return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err) } iniProfile, err := config.GetSection(profile) if err != nil { return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to get profile", err) } id, err := iniProfile.GetKey("aws_access_key_id") if err != nil { return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsAccessKey", fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename), err) } secret, err := iniProfile.GetKey("aws_secret_access_key") if err != nil { return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsSecret", fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename), nil) } // Default to empty string if not found token := iniProfile.Key("aws_session_token") return Value{ AccessKeyID: id.String(), SecretAccessKey: secret.String(), SessionToken: token.String(), ProviderName: SharedCredsProviderName, }, nil } // filename returns the filename to use to read AWS shared credentials. // // Will return an error if the user's home directory path cannot be found. func (p *SharedCredentialsProvider) filename() (string, error) { if p.Filename == "" { if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); p.Filename != "" { return p.Filename, nil } homeDir := os.Getenv("HOME") // *nix if homeDir == "" { // Windows homeDir = os.Getenv("USERPROFILE") } if homeDir == "" { return "", ErrSharedCredentialsHomeNotFound } p.Filename = filepath.Join(homeDir, ".aws", "credentials") } return p.Filename, nil } // profile returns the AWS shared credentials profile. If empty will read // environment variable "AWS_PROFILE". If that is not set profile will // return "default". func (p *SharedCredentialsProvider) profile() string { if p.Profile == "" { p.Profile = os.Getenv("AWS_PROFILE") } if p.Profile == "" { p.Profile = "default" } return p.Profile } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go ================================================ package credentials import ( "github.com/aws/aws-sdk-go/aws/awserr" ) // StaticProviderName provides a name of Static provider const StaticProviderName = "StaticProvider" var ( // ErrStaticCredentialsEmpty is emitted when static credentials are empty. // // @readonly ErrStaticCredentialsEmpty = awserr.New("EmptyStaticCreds", "static credentials are empty", nil) ) // A StaticProvider is a set of credentials which are set programmatically, // and will never expire. type StaticProvider struct { Value } // NewStaticCredentials returns a pointer to a new Credentials object // wrapping a static credentials value provider. func NewStaticCredentials(id, secret, token string) *Credentials { return NewCredentials(&StaticProvider{Value: Value{ AccessKeyID: id, SecretAccessKey: secret, SessionToken: token, }}) } // NewStaticCredentialsFromCreds returns a pointer to a new Credentials object // wrapping the static credentials value provide. Same as NewStaticCredentials // but takes the creds Value instead of individual fields func NewStaticCredentialsFromCreds(creds Value) *Credentials { return NewCredentials(&StaticProvider{Value: creds}) } // Retrieve returns the credentials or error if the credentials are invalid. func (s *StaticProvider) Retrieve() (Value, error) { if s.AccessKeyID == "" || s.SecretAccessKey == "" { return Value{ProviderName: StaticProviderName}, ErrStaticCredentialsEmpty } if len(s.Value.ProviderName) == 0 { s.Value.ProviderName = StaticProviderName } return s.Value, nil } // IsExpired returns if the credentials are expired. // // For StaticProvider, the credentials never expired. func (s *StaticProvider) IsExpired() bool { return false } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go ================================================ // Package stscreds are credential Providers to retrieve STS AWS credentials. // // STS provides multiple ways to retrieve credentials which can be used when making // future AWS service API operation calls. package stscreds import ( "fmt" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/service/sts" ) // ProviderName provides a name of AssumeRole provider const ProviderName = "AssumeRoleProvider" // AssumeRoler represents the minimal subset of the STS client API used by this provider. type AssumeRoler interface { AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) } // DefaultDuration is the default amount of time in minutes that the credentials // will be valid for. var DefaultDuration = time.Duration(15) * time.Minute // AssumeRoleProvider retrieves temporary credentials from the STS service, and // keeps track of their expiration time. This provider must be used explicitly, // as it is not included in the credentials chain. type AssumeRoleProvider struct { credentials.Expiry // STS client to make assume role request with. Client AssumeRoler // Role to be assumed. RoleARN string // Session name, if you wish to reuse the credentials elsewhere. RoleSessionName string // Expiry duration of the STS credentials. Defaults to 15 minutes if not set. Duration time.Duration // Optional ExternalID to pass along, defaults to nil if not set. ExternalID *string // The policy plain text must be 2048 bytes or shorter. However, an internal // conversion compresses it into a packed binary format with a separate limit. // The PackedPolicySize response element indicates by percentage how close to // the upper size limit the policy is, with 100% equaling the maximum allowed // size. Policy *string // The identification number of the MFA device that is associated with the user // who is making the AssumeRole call. Specify this value if the trust policy // of the role being assumed includes a condition that requires MFA authentication. // The value is either the serial number for a hardware device (such as GAHT12345678) // or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user). SerialNumber *string // The value provided by the MFA device, if the trust policy of the role being // assumed requires MFA (that is, if the policy includes a condition that tests // for MFA). If the role being assumed requires MFA and if the TokenCode value // is missing or expired, the AssumeRole call returns an "access denied" error. TokenCode *string // ExpiryWindow will allow the credentials to trigger refreshing prior to // the credentials actually expiring. This is beneficial so race conditions // with expiring credentials do not cause request to fail unexpectedly // due to ExpiredTokenException exceptions. // // So a ExpiryWindow of 10s would cause calls to IsExpired() to return true // 10 seconds before the credentials are actually expired. // // If ExpiryWindow is 0 or less it will be ignored. ExpiryWindow time.Duration } // NewCredentials returns a pointer to a new Credentials object wrapping the // AssumeRoleProvider. The credentials will expire every 15 minutes and the // role will be named after a nanosecond timestamp of this operation. // // Takes a Config provider to create the STS client. The ConfigProvider is // satisfied by the session.Session type. func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials { p := &AssumeRoleProvider{ Client: sts.New(c), RoleARN: roleARN, Duration: DefaultDuration, } for _, option := range options { option(p) } return credentials.NewCredentials(p) } // NewCredentialsWithClient returns a pointer to a new Credentials object wrapping the // AssumeRoleProvider. The credentials will expire every 15 minutes and the // role will be named after a nanosecond timestamp of this operation. // // Takes an AssumeRoler which can be satisfiede by the STS client. func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials { p := &AssumeRoleProvider{ Client: svc, RoleARN: roleARN, Duration: DefaultDuration, } for _, option := range options { option(p) } return credentials.NewCredentials(p) } // Retrieve generates a new set of temporary credentials using STS. func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) { // Apply defaults where parameters are not set. if p.RoleSessionName == "" { // Try to work out a role name that will hopefully end up unique. p.RoleSessionName = fmt.Sprintf("%d", time.Now().UTC().UnixNano()) } if p.Duration == 0 { // Expire as often as AWS permits. p.Duration = DefaultDuration } input := &sts.AssumeRoleInput{ DurationSeconds: aws.Int64(int64(p.Duration / time.Second)), RoleArn: aws.String(p.RoleARN), RoleSessionName: aws.String(p.RoleSessionName), ExternalId: p.ExternalID, } if p.Policy != nil { input.Policy = p.Policy } if p.SerialNumber != nil && p.TokenCode != nil { input.SerialNumber = p.SerialNumber input.TokenCode = p.TokenCode } roleOutput, err := p.Client.AssumeRole(input) if err != nil { return credentials.Value{ProviderName: ProviderName}, err } // We will proactively generate new credentials before they expire. p.SetExpiration(*roleOutput.Credentials.Expiration, p.ExpiryWindow) return credentials.Value{ AccessKeyID: *roleOutput.Credentials.AccessKeyId, SecretAccessKey: *roleOutput.Credentials.SecretAccessKey, SessionToken: *roleOutput.Credentials.SessionToken, ProviderName: ProviderName, }, nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go ================================================ // Package defaults is a collection of helpers to retrieve the SDK's default // configuration and handlers. // // Generally this package shouldn't be used directly, but session.Session // instead. This package is useful when you need to reset the defaults // of a session or service client to the SDK defaults before setting // additional parameters. package defaults import ( "fmt" "net/http" "os" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/corehandlers" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/private/endpoints" ) // A Defaults provides a collection of default values for SDK clients. type Defaults struct { Config *aws.Config Handlers request.Handlers } // Get returns the SDK's default values with Config and handlers pre-configured. func Get() Defaults { cfg := Config() handlers := Handlers() cfg.Credentials = CredChain(cfg, handlers) return Defaults{ Config: cfg, Handlers: handlers, } } // Config returns the default configuration without credentials. // To retrieve a config with credentials also included use // `defaults.Get().Config` instead. // // Generally you shouldn't need to use this method directly, but // is available if you need to reset the configuration of an // existing service client or session. func Config() *aws.Config { return aws.NewConfig(). WithCredentials(credentials.AnonymousCredentials). WithRegion(os.Getenv("AWS_REGION")). WithHTTPClient(http.DefaultClient). WithMaxRetries(aws.UseServiceDefaultRetries). WithLogger(aws.NewDefaultLogger()). WithLogLevel(aws.LogOff). WithSleepDelay(time.Sleep) } // Handlers returns the default request handlers. // // Generally you shouldn't need to use this method directly, but // is available if you need to reset the request handlers of an // existing service client or session. func Handlers() request.Handlers { var handlers request.Handlers handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler) handlers.Validate.AfterEachFn = request.HandlerListStopOnError handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler) handlers.Build.AfterEachFn = request.HandlerListStopOnError handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler) handlers.Send.PushBackNamed(corehandlers.SendHandler) handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler) handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler) return handlers } // CredChain returns the default credential chain. // // Generally you shouldn't need to use this method directly, but // is available if you need to reset the credentials of an // existing service client or session's Config. func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials { return credentials.NewCredentials(&credentials.ChainProvider{ VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors), Providers: []credentials.Provider{ &credentials.EnvProvider{}, &credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, RemoteCredProvider(*cfg, handlers), }, }) } // RemoteCredProvider returns a credenitials provider for the default remote // endpoints such as EC2 or ECS Roles. func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider { ecsCredURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") if len(ecsCredURI) > 0 { return ecsCredProvider(cfg, handlers, ecsCredURI) } return ec2RoleProvider(cfg, handlers) } func ecsCredProvider(cfg aws.Config, handlers request.Handlers, uri string) credentials.Provider { const host = `169.254.170.2` return endpointcreds.NewProviderClient(cfg, handlers, fmt.Sprintf("http://%s%s", host, uri), func(p *endpointcreds.Provider) { p.ExpiryWindow = 5 * time.Minute }, ) } func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider { endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName, aws.StringValue(cfg.Region), true, false) return &ec2rolecreds.EC2RoleProvider{ Client: ec2metadata.NewClient(cfg, handlers, endpoint, signingRegion), ExpiryWindow: 5 * time.Minute, } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go ================================================ package ec2metadata import ( "encoding/json" "fmt" "path" "strings" "time" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" ) // GetMetadata uses the path provided to request information from the EC2 // instance metdata service. The content will be returned as a string, or // error if the request failed. func (c *EC2Metadata) GetMetadata(p string) (string, error) { op := &request.Operation{ Name: "GetMetadata", HTTPMethod: "GET", HTTPPath: path.Join("/", "meta-data", p), } output := &metadataOutput{} req := c.NewRequest(op, nil, output) return output.Content, req.Send() } // GetDynamicData uses the path provided to request information from the EC2 // instance metadata service for dynamic data. The content will be returned // as a string, or error if the request failed. func (c *EC2Metadata) GetDynamicData(p string) (string, error) { op := &request.Operation{ Name: "GetDynamicData", HTTPMethod: "GET", HTTPPath: path.Join("/", "dynamic", p), } output := &metadataOutput{} req := c.NewRequest(op, nil, output) return output.Content, req.Send() } // GetInstanceIdentityDocument retrieves an identity document describing an // instance. Error is returned if the request fails or is unable to parse // the response. func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) { resp, err := c.GetDynamicData("instance-identity/document") if err != nil { return EC2InstanceIdentityDocument{}, awserr.New("EC2MetadataRequestError", "failed to get EC2 instance identity document", err) } doc := EC2InstanceIdentityDocument{} if err := json.NewDecoder(strings.NewReader(resp)).Decode(&doc); err != nil { return EC2InstanceIdentityDocument{}, awserr.New("SerializationError", "failed to decode EC2 instance identity document", err) } return doc, nil } // IAMInfo retrieves IAM info from the metadata API func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) { resp, err := c.GetMetadata("iam/info") if err != nil { return EC2IAMInfo{}, awserr.New("EC2MetadataRequestError", "failed to get EC2 IAM info", err) } info := EC2IAMInfo{} if err := json.NewDecoder(strings.NewReader(resp)).Decode(&info); err != nil { return EC2IAMInfo{}, awserr.New("SerializationError", "failed to decode EC2 IAM info", err) } if info.Code != "Success" { errMsg := fmt.Sprintf("failed to get EC2 IAM Info (%s)", info.Code) return EC2IAMInfo{}, awserr.New("EC2MetadataError", errMsg, nil) } return info, nil } // Region returns the region the instance is running in. func (c *EC2Metadata) Region() (string, error) { resp, err := c.GetMetadata("placement/availability-zone") if err != nil { return "", err } // returns region without the suffix. Eg: us-west-2a becomes us-west-2 return resp[:len(resp)-1], nil } // Available returns if the application has access to the EC2 Metadata service. // Can be used to determine if application is running within an EC2 Instance and // the metadata service is available. func (c *EC2Metadata) Available() bool { if _, err := c.GetMetadata("instance-id"); err != nil { return false } return true } // An EC2IAMInfo provides the shape for unmarshalling // an IAM info from the metadata API type EC2IAMInfo struct { Code string LastUpdated time.Time InstanceProfileArn string InstanceProfileID string } // An EC2InstanceIdentityDocument provides the shape for unmarshalling // an instance identity document type EC2InstanceIdentityDocument struct { DevpayProductCodes []string `json:"devpayProductCodes"` AvailabilityZone string `json:"availabilityZone"` PrivateIP string `json:"privateIp"` Version string `json:"version"` Region string `json:"region"` InstanceID string `json:"instanceId"` BillingProducts []string `json:"billingProducts"` InstanceType string `json:"instanceType"` AccountID string `json:"accountId"` PendingTime time.Time `json:"pendingTime"` ImageID string `json:"imageId"` KernelID string `json:"kernelId"` RamdiskID string `json:"ramdiskId"` Architecture string `json:"architecture"` } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go ================================================ // Package ec2metadata provides the client for making API calls to the // EC2 Metadata service. package ec2metadata import ( "bytes" "errors" "io" "net/http" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/client/metadata" "github.com/aws/aws-sdk-go/aws/request" ) // ServiceName is the name of the service. const ServiceName = "ec2metadata" // A EC2Metadata is an EC2 Metadata service Client. type EC2Metadata struct { *client.Client } // New creates a new instance of the EC2Metadata client with a session. // This client is safe to use across multiple goroutines. // // // Example: // // Create a EC2Metadata client from just a session. // svc := ec2metadata.New(mySession) // // // Create a EC2Metadata client with additional configuration // svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody)) func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata { c := p.ClientConfig(ServiceName, cfgs...) return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion) } // NewClient returns a new EC2Metadata client. Should be used to create // a client when not using a session. Generally using just New with a session // is preferred. // // If an unmodified HTTP client is provided from the stdlib default, or no client // the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened. // To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default. func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata { if !aws.BoolValue(cfg.EC2MetadataDisableTimeoutOverride) && httpClientZero(cfg.HTTPClient) { // If the http client is unmodified and this feature is not disabled // set custom timeouts for EC2Metadata requests. cfg.HTTPClient = &http.Client{ // use a shorter timeout than default because the metadata // service is local if it is running, and to fail faster // if not running on an ec2 instance. Timeout: 5 * time.Second, } } svc := &EC2Metadata{ Client: client.New( cfg, metadata.ClientInfo{ ServiceName: ServiceName, Endpoint: endpoint, APIVersion: "latest", }, handlers, ), } svc.Handlers.Unmarshal.PushBack(unmarshalHandler) svc.Handlers.UnmarshalError.PushBack(unmarshalError) svc.Handlers.Validate.Clear() svc.Handlers.Validate.PushBack(validateEndpointHandler) // Add additional options to the service config for _, option := range opts { option(svc.Client) } return svc } func httpClientZero(c *http.Client) bool { return c == nil || (c.Transport == nil && c.CheckRedirect == nil && c.Jar == nil && c.Timeout == 0) } type metadataOutput struct { Content string } func unmarshalHandler(r *request.Request) { defer r.HTTPResponse.Body.Close() b := &bytes.Buffer{} if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil { r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err) return } if data, ok := r.Data.(*metadataOutput); ok { data.Content = b.String() } } func unmarshalError(r *request.Request) { defer r.HTTPResponse.Body.Close() b := &bytes.Buffer{} if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil { r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err) return } // Response body format is not consistent between metadata endpoints. // Grab the error message as a string and include that as the source error r.Error = awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String())) } func validateEndpointHandler(r *request.Request) { if r.ClientInfo.Endpoint == "" { r.Error = aws.ErrMissingEndpoint } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/errors.go ================================================ package aws import "github.com/aws/aws-sdk-go/aws/awserr" var ( // ErrMissingRegion is an error that is returned if region configuration is // not found. // // @readonly ErrMissingRegion = awserr.New("MissingRegion", "could not find region configuration", nil) // ErrMissingEndpoint is an error that is returned if an endpoint cannot be // resolved for a service. // // @readonly ErrMissingEndpoint = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil) ) ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/logger.go ================================================ package aws import ( "log" "os" ) // A LogLevelType defines the level logging should be performed at. Used to instruct // the SDK which statements should be logged. type LogLevelType uint // LogLevel returns the pointer to a LogLevel. Should be used to workaround // not being able to take the address of a non-composite literal. func LogLevel(l LogLevelType) *LogLevelType { return &l } // Value returns the LogLevel value or the default value LogOff if the LogLevel // is nil. Safe to use on nil value LogLevelTypes. func (l *LogLevelType) Value() LogLevelType { if l != nil { return *l } return LogOff } // Matches returns true if the v LogLevel is enabled by this LogLevel. Should be // used with logging sub levels. Is safe to use on nil value LogLevelTypes. If // LogLevel is nill, will default to LogOff comparison. func (l *LogLevelType) Matches(v LogLevelType) bool { c := l.Value() return c&v == v } // AtLeast returns true if this LogLevel is at least high enough to satisfies v. // Is safe to use on nil value LogLevelTypes. If LogLevel is nill, will default // to LogOff comparison. func (l *LogLevelType) AtLeast(v LogLevelType) bool { c := l.Value() return c >= v } const ( // LogOff states that no logging should be performed by the SDK. This is the // default state of the SDK, and should be use to disable all logging. LogOff LogLevelType = iota * 0x1000 // LogDebug state that debug output should be logged by the SDK. This should // be used to inspect request made and responses received. LogDebug ) // Debug Logging Sub Levels const ( // LogDebugWithSigning states that the SDK should log request signing and // presigning events. This should be used to log the signing details of // requests for debugging. Will also enable LogDebug. LogDebugWithSigning LogLevelType = LogDebug | (1 << iota) // LogDebugWithHTTPBody states the SDK should log HTTP request and response // HTTP bodys in addition to the headers and path. This should be used to // see the body content of requests and responses made while using the SDK // Will also enable LogDebug. LogDebugWithHTTPBody // LogDebugWithRequestRetries states the SDK should log when service requests will // be retried. This should be used to log when you want to log when service // requests are being retried. Will also enable LogDebug. LogDebugWithRequestRetries // LogDebugWithRequestErrors states the SDK should log when service requests fail // to build, send, validate, or unmarshal. LogDebugWithRequestErrors ) // A Logger is a minimalistic interface for the SDK to log messages to. Should // be used to provide custom logging writers for the SDK to use. type Logger interface { Log(...interface{}) } // A LoggerFunc is a convenience type to convert a function taking a variadic // list of arguments and wrap it so the Logger interface can be used. // // Example: // s3.New(sess, &aws.Config{Logger: aws.LoggerFunc(func(args ...interface{}) { // fmt.Fprintln(os.Stdout, args...) // })}) type LoggerFunc func(...interface{}) // Log calls the wrapped function with the arguments provided func (f LoggerFunc) Log(args ...interface{}) { f(args...) } // NewDefaultLogger returns a Logger which will write log messages to stdout, and // use same formatting runes as the stdlib log.Logger func NewDefaultLogger() Logger { return &defaultLogger{ logger: log.New(os.Stdout, "", log.LstdFlags), } } // A defaultLogger provides a minimalistic logger satisfying the Logger interface. type defaultLogger struct { logger *log.Logger } // Log logs the parameters to the stdlib logger. See log.Println. func (l defaultLogger) Log(args ...interface{}) { l.logger.Println(args...) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/request/handlers.go ================================================ package request import ( "fmt" "strings" ) // A Handlers provides a collection of request handlers for various // stages of handling requests. type Handlers struct { Validate HandlerList Build HandlerList Sign HandlerList Send HandlerList ValidateResponse HandlerList Unmarshal HandlerList UnmarshalMeta HandlerList UnmarshalError HandlerList Retry HandlerList AfterRetry HandlerList } // Copy returns of this handler's lists. func (h *Handlers) Copy() Handlers { return Handlers{ Validate: h.Validate.copy(), Build: h.Build.copy(), Sign: h.Sign.copy(), Send: h.Send.copy(), ValidateResponse: h.ValidateResponse.copy(), Unmarshal: h.Unmarshal.copy(), UnmarshalError: h.UnmarshalError.copy(), UnmarshalMeta: h.UnmarshalMeta.copy(), Retry: h.Retry.copy(), AfterRetry: h.AfterRetry.copy(), } } // Clear removes callback functions for all handlers func (h *Handlers) Clear() { h.Validate.Clear() h.Build.Clear() h.Send.Clear() h.Sign.Clear() h.Unmarshal.Clear() h.UnmarshalMeta.Clear() h.UnmarshalError.Clear() h.ValidateResponse.Clear() h.Retry.Clear() h.AfterRetry.Clear() } // A HandlerListRunItem represents an entry in the HandlerList which // is being run. type HandlerListRunItem struct { Index int Handler NamedHandler Request *Request } // A HandlerList manages zero or more handlers in a list. type HandlerList struct { list []NamedHandler // Called after each request handler in the list is called. If set // and the func returns true the HandlerList will continue to iterate // over the request handlers. If false is returned the HandlerList // will stop iterating. // // Should be used if extra logic to be performed between each handler // in the list. This can be used to terminate a list's iteration // based on a condition such as error like, HandlerListStopOnError. // Or for logging like HandlerListLogItem. AfterEachFn func(item HandlerListRunItem) bool } // A NamedHandler is a struct that contains a name and function callback. type NamedHandler struct { Name string Fn func(*Request) } // copy creates a copy of the handler list. func (l *HandlerList) copy() HandlerList { n := HandlerList{ AfterEachFn: l.AfterEachFn, } n.list = append([]NamedHandler{}, l.list...) return n } // Clear clears the handler list. func (l *HandlerList) Clear() { l.list = []NamedHandler{} } // Len returns the number of handlers in the list. func (l *HandlerList) Len() int { return len(l.list) } // PushBack pushes handler f to the back of the handler list. func (l *HandlerList) PushBack(f func(*Request)) { l.list = append(l.list, NamedHandler{"__anonymous", f}) } // PushFront pushes handler f to the front of the handler list. func (l *HandlerList) PushFront(f func(*Request)) { l.list = append([]NamedHandler{{"__anonymous", f}}, l.list...) } // PushBackNamed pushes named handler f to the back of the handler list. func (l *HandlerList) PushBackNamed(n NamedHandler) { l.list = append(l.list, n) } // PushFrontNamed pushes named handler f to the front of the handler list. func (l *HandlerList) PushFrontNamed(n NamedHandler) { l.list = append([]NamedHandler{n}, l.list...) } // Remove removes a NamedHandler n func (l *HandlerList) Remove(n NamedHandler) { newlist := []NamedHandler{} for _, m := range l.list { if m.Name != n.Name { newlist = append(newlist, m) } } l.list = newlist } // Run executes all handlers in the list with a given request object. func (l *HandlerList) Run(r *Request) { for i, h := range l.list { h.Fn(r) item := HandlerListRunItem{ Index: i, Handler: h, Request: r, } if l.AfterEachFn != nil && !l.AfterEachFn(item) { return } } } // HandlerListLogItem logs the request handler and the state of the // request's Error value. Always returns true to continue iterating // request handlers in a HandlerList. func HandlerListLogItem(item HandlerListRunItem) bool { if item.Request.Config.Logger == nil { return true } item.Request.Config.Logger.Log("DEBUG: RequestHandler", item.Index, item.Handler.Name, item.Request.Error) return true } // HandlerListStopOnError returns false to stop the HandlerList iterating // over request handlers if Request.Error is not nil. True otherwise // to continue iterating. func HandlerListStopOnError(item HandlerListRunItem) bool { return item.Request.Error == nil } // MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request // header. If the extra parameters are provided they will be added as metadata to the // name/version pair resulting in the following format. // "name/version (extra0; extra1; ...)" // The user agent part will be concatenated with this current request's user agent string. func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) { ua := fmt.Sprintf("%s/%s", name, version) if len(extra) > 0 { ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; ")) } return func(r *Request) { AddToUserAgent(r, ua) } } // MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header. // The input string will be concatenated with the current request's user agent string. func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) { return func(r *Request) { AddToUserAgent(r, s) } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/request/http_request.go ================================================ // +build go1.5 package request import ( "io" "net/http" "net/url" ) func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request { req := &http.Request{ URL: &url.URL{}, Header: http.Header{}, Close: r.Close, Body: body, Host: r.Host, Method: r.Method, Proto: r.Proto, ContentLength: r.ContentLength, // Cancel will be deprecated in 1.7 and will be replaced with Context Cancel: r.Cancel, } *req.URL = *r.URL for k, v := range r.Header { for _, vv := range v { req.Header.Add(k, vv) } } return req } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/request/http_request_1_4.go ================================================ // +build !go1.5 package request import ( "io" "net/http" "net/url" ) func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request { req := &http.Request{ URL: &url.URL{}, Header: http.Header{}, Close: r.Close, Body: body, Host: r.Host, Method: r.Method, Proto: r.Proto, ContentLength: r.ContentLength, } *req.URL = *r.URL for k, v := range r.Header { for _, vv := range v { req.Header.Add(k, vv) } } return req } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader.go ================================================ package request import ( "io" "sync" ) // offsetReader is a thread-safe io.ReadCloser to prevent racing // with retrying requests type offsetReader struct { buf io.ReadSeeker lock sync.RWMutex closed bool } func newOffsetReader(buf io.ReadSeeker, offset int64) *offsetReader { reader := &offsetReader{} buf.Seek(offset, 0) reader.buf = buf return reader } // Close is a thread-safe close. Uses the write lock. func (o *offsetReader) Close() error { o.lock.Lock() defer o.lock.Unlock() o.closed = true return nil } // Read is a thread-safe read using a read lock. func (o *offsetReader) Read(p []byte) (int, error) { o.lock.RLock() defer o.lock.RUnlock() if o.closed { return 0, io.EOF } return o.buf.Read(p) } // CloseAndCopy will return a new offsetReader with a copy of the old buffer // and close the old buffer. func (o *offsetReader) CloseAndCopy(offset int64) *offsetReader { o.Close() return newOffsetReader(o.buf, offset) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/request/request.go ================================================ package request import ( "bytes" "fmt" "io" "io/ioutil" "net/http" "net/url" "reflect" "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/client/metadata" ) // A Request is the service request to be made. type Request struct { Config aws.Config ClientInfo metadata.ClientInfo Handlers Handlers Retryer Time time.Time ExpireTime time.Duration Operation *Operation HTTPRequest *http.Request HTTPResponse *http.Response Body io.ReadSeeker BodyStart int64 // offset from beginning of Body that the request body starts Params interface{} Error error Data interface{} RequestID string RetryCount int Retryable *bool RetryDelay time.Duration NotHoist bool SignedHeaderVals http.Header LastSignedAt time.Time built bool } // An Operation is the service API operation to be made. type Operation struct { Name string HTTPMethod string HTTPPath string *Paginator } // Paginator keeps track of pagination configuration for an API operation. type Paginator struct { InputTokens []string OutputTokens []string LimitToken string TruncationToken string } // New returns a new Request pointer for the service API // operation and parameters. // // Params is any value of input parameters to be the request payload. // Data is pointer value to an object which the request's response // payload will be deserialized to. func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers, retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request { method := operation.HTTPMethod if method == "" { method = "POST" } httpReq, _ := http.NewRequest(method, "", nil) var err error httpReq.URL, err = url.Parse(clientInfo.Endpoint + operation.HTTPPath) if err != nil { httpReq.URL = &url.URL{} err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err) } r := &Request{ Config: cfg, ClientInfo: clientInfo, Handlers: handlers.Copy(), Retryer: retryer, Time: time.Now(), ExpireTime: 0, Operation: operation, HTTPRequest: httpReq, Body: nil, Params: params, Error: err, Data: data, } r.SetBufferBody([]byte{}) return r } // WillRetry returns if the request's can be retried. func (r *Request) WillRetry() bool { return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.MaxRetries() } // ParamsFilled returns if the request's parameters have been populated // and the parameters are valid. False is returned if no parameters are // provided or invalid. func (r *Request) ParamsFilled() bool { return r.Params != nil && reflect.ValueOf(r.Params).Elem().IsValid() } // DataFilled returns true if the request's data for response deserialization // target has been set and is a valid. False is returned if data is not // set, or is invalid. func (r *Request) DataFilled() bool { return r.Data != nil && reflect.ValueOf(r.Data).Elem().IsValid() } // SetBufferBody will set the request's body bytes that will be sent to // the service API. func (r *Request) SetBufferBody(buf []byte) { r.SetReaderBody(bytes.NewReader(buf)) } // SetStringBody sets the body of the request to be backed by a string. func (r *Request) SetStringBody(s string) { r.SetReaderBody(strings.NewReader(s)) } // SetReaderBody will set the request's body reader. func (r *Request) SetReaderBody(reader io.ReadSeeker) { r.HTTPRequest.Body = newOffsetReader(reader, 0) r.Body = reader } // Presign returns the request's signed URL. Error will be returned // if the signing fails. func (r *Request) Presign(expireTime time.Duration) (string, error) { r.ExpireTime = expireTime r.NotHoist = false r.Sign() if r.Error != nil { return "", r.Error } return r.HTTPRequest.URL.String(), nil } // PresignRequest behaves just like presign, but hoists all headers and signs them. // Also returns the signed hash back to the user func (r *Request) PresignRequest(expireTime time.Duration) (string, http.Header, error) { r.ExpireTime = expireTime r.NotHoist = true r.Sign() if r.Error != nil { return "", nil, r.Error } return r.HTTPRequest.URL.String(), r.SignedHeaderVals, nil } func debugLogReqError(r *Request, stage string, retrying bool, err error) { if !r.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) { return } retryStr := "not retrying" if retrying { retryStr = "will retry" } r.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v", stage, r.ClientInfo.ServiceName, r.Operation.Name, retryStr, err)) } // Build will build the request's object so it can be signed and sent // to the service. Build will also validate all the request's parameters. // Anny additional build Handlers set on this request will be run // in the order they were set. // // The request will only be built once. Multiple calls to build will have // no effect. // // If any Validate or Build errors occur the build will stop and the error // which occurred will be returned. func (r *Request) Build() error { if !r.built { r.Handlers.Validate.Run(r) if r.Error != nil { debugLogReqError(r, "Validate Request", false, r.Error) return r.Error } r.Handlers.Build.Run(r) if r.Error != nil { debugLogReqError(r, "Build Request", false, r.Error) return r.Error } r.built = true } return r.Error } // Sign will sign the request returning error if errors are encountered. // // Send will build the request prior to signing. All Sign Handlers will // be executed in the order they were set. func (r *Request) Sign() error { r.Build() if r.Error != nil { debugLogReqError(r, "Build Request", false, r.Error) return r.Error } r.Handlers.Sign.Run(r) return r.Error } // Send will send the request returning error if errors are encountered. // // Send will sign the request prior to sending. All Send Handlers will // be executed in the order they were set. // // Canceling a request is non-deterministic. If a request has been canceled, // then the transport will choose, randomly, one of the state channels during // reads or getting the connection. // // readLoop() and getConn(req *Request, cm connectMethod) // https://github.com/golang/go/blob/master/src/net/http/transport.go func (r *Request) Send() error { for { if aws.BoolValue(r.Retryable) { if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) { r.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d", r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount)) } var body io.ReadCloser if reader, ok := r.HTTPRequest.Body.(*offsetReader); ok { body = reader.CloseAndCopy(r.BodyStart) } else { if r.Config.Logger != nil { r.Config.Logger.Log("Request body type has been overwritten. May cause race conditions") } r.Body.Seek(r.BodyStart, 0) body = ioutil.NopCloser(r.Body) } r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, body) if r.HTTPResponse != nil && r.HTTPResponse.Body != nil { // Closing response body. Since we are setting a new request to send off, this // response will get squashed and leaked. r.HTTPResponse.Body.Close() } } r.Sign() if r.Error != nil { return r.Error } r.Retryable = nil r.Handlers.Send.Run(r) if r.Error != nil { if strings.Contains(r.Error.Error(), "net/http: request canceled") { return r.Error } err := r.Error r.Handlers.Retry.Run(r) r.Handlers.AfterRetry.Run(r) if r.Error != nil { debugLogReqError(r, "Send Request", false, r.Error) return r.Error } debugLogReqError(r, "Send Request", true, err) continue } r.Handlers.UnmarshalMeta.Run(r) r.Handlers.ValidateResponse.Run(r) if r.Error != nil { err := r.Error r.Handlers.UnmarshalError.Run(r) r.Handlers.Retry.Run(r) r.Handlers.AfterRetry.Run(r) if r.Error != nil { debugLogReqError(r, "Validate Response", false, r.Error) return r.Error } debugLogReqError(r, "Validate Response", true, err) continue } r.Handlers.Unmarshal.Run(r) if r.Error != nil { err := r.Error r.Handlers.Retry.Run(r) r.Handlers.AfterRetry.Run(r) if r.Error != nil { debugLogReqError(r, "Unmarshal Response", false, r.Error) return r.Error } debugLogReqError(r, "Unmarshal Response", true, err) continue } break } return nil } // AddToUserAgent adds the string to the end of the request's current user agent. func AddToUserAgent(r *Request, s string) { curUA := r.HTTPRequest.Header.Get("User-Agent") if len(curUA) > 0 { s = curUA + " " + s } r.HTTPRequest.Header.Set("User-Agent", s) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination.go ================================================ package request import ( "reflect" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awsutil" ) //type Paginater interface { // HasNextPage() bool // NextPage() *Request // EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error //} // HasNextPage returns true if this request has more pages of data available. func (r *Request) HasNextPage() bool { return len(r.nextPageTokens()) > 0 } // nextPageTokens returns the tokens to use when asking for the next page of // data. func (r *Request) nextPageTokens() []interface{} { if r.Operation.Paginator == nil { return nil } if r.Operation.TruncationToken != "" { tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken) if len(tr) == 0 { return nil } switch v := tr[0].(type) { case *bool: if !aws.BoolValue(v) { return nil } case bool: if v == false { return nil } } } tokens := []interface{}{} tokenAdded := false for _, outToken := range r.Operation.OutputTokens { v, _ := awsutil.ValuesAtPath(r.Data, outToken) if len(v) > 0 { tokens = append(tokens, v[0]) tokenAdded = true } else { tokens = append(tokens, nil) } } if !tokenAdded { return nil } return tokens } // NextPage returns a new Request that can be executed to return the next // page of result data. Call .Send() on this request to execute it. func (r *Request) NextPage() *Request { tokens := r.nextPageTokens() if len(tokens) == 0 { return nil } data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface() nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data) for i, intok := range nr.Operation.InputTokens { awsutil.SetValueAtPath(nr.Params, intok, tokens[i]) } return nr } // EachPage iterates over each page of a paginated request object. The fn // parameter should be a function with the following sample signature: // // func(page *T, lastPage bool) bool { // return true // return false to stop iterating // } // // Where "T" is the structure type matching the output structure of the given // operation. For example, a request object generated by // DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput // as the structure "T". The lastPage value represents whether the page is // the last page of data or not. The return value of this function should // return true to keep iterating or false to stop. func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error { for page := r; page != nil; page = page.NextPage() { if err := page.Send(); err != nil { return err } if getNextPage := fn(page.Data, !page.HasNextPage()); !getNextPage { return page.Error } } return nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/request/retryer.go ================================================ package request import ( "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" ) // Retryer is an interface to control retry logic for a given service. // The default implementation used by most services is the service.DefaultRetryer // structure, which contains basic retry logic using exponential backoff. type Retryer interface { RetryRules(*Request) time.Duration ShouldRetry(*Request) bool MaxRetries() int } // WithRetryer sets a config Retryer value to the given Config returning it // for chaining. func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config { cfg.Retryer = retryer return cfg } // retryableCodes is a collection of service response codes which are retry-able // without any further action. var retryableCodes = map[string]struct{}{ "RequestError": {}, "RequestTimeout": {}, } var throttleCodes = map[string]struct{}{ "ProvisionedThroughputExceededException": {}, "Throttling": {}, "ThrottlingException": {}, "RequestLimitExceeded": {}, "RequestThrottled": {}, "LimitExceededException": {}, // Deleting 10+ DynamoDb tables at once "TooManyRequestsException": {}, // Lambda functions } // credsExpiredCodes is a collection of error codes which signify the credentials // need to be refreshed. Expired tokens require refreshing of credentials, and // resigning before the request can be retried. var credsExpiredCodes = map[string]struct{}{ "ExpiredToken": {}, "ExpiredTokenException": {}, "RequestExpired": {}, // EC2 Only } func isCodeThrottle(code string) bool { _, ok := throttleCodes[code] return ok } func isCodeRetryable(code string) bool { if _, ok := retryableCodes[code]; ok { return true } return isCodeExpiredCreds(code) } func isCodeExpiredCreds(code string) bool { _, ok := credsExpiredCodes[code] return ok } // IsErrorRetryable returns whether the error is retryable, based on its Code. // Returns false if the request has no Error set. func (r *Request) IsErrorRetryable() bool { if r.Error != nil { if err, ok := r.Error.(awserr.Error); ok { return isCodeRetryable(err.Code()) } } return false } // IsErrorThrottle returns whether the error is to be throttled based on its code. // Returns false if the request has no Error set func (r *Request) IsErrorThrottle() bool { if r.Error != nil { if err, ok := r.Error.(awserr.Error); ok { return isCodeThrottle(err.Code()) } } return false } // IsErrorExpired returns whether the error code is a credential expiry error. // Returns false if the request has no Error set. func (r *Request) IsErrorExpired() bool { if r.Error != nil { if err, ok := r.Error.(awserr.Error); ok { return isCodeExpiredCreds(err.Code()) } } return false } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/request/validation.go ================================================ package request import ( "bytes" "fmt" "github.com/aws/aws-sdk-go/aws/awserr" ) const ( // InvalidParameterErrCode is the error code for invalid parameters errors InvalidParameterErrCode = "InvalidParameter" // ParamRequiredErrCode is the error code for required parameter errors ParamRequiredErrCode = "ParamRequiredError" // ParamMinValueErrCode is the error code for fields with too low of a // number value. ParamMinValueErrCode = "ParamMinValueError" // ParamMinLenErrCode is the error code for fields without enough elements. ParamMinLenErrCode = "ParamMinLenError" ) // Validator provides a way for types to perform validation logic on their // input values that external code can use to determine if a type's values // are valid. type Validator interface { Validate() error } // An ErrInvalidParams provides wrapping of invalid parameter errors found when // validating API operation input parameters. type ErrInvalidParams struct { // Context is the base context of the invalid parameter group. Context string errs []ErrInvalidParam } // Add adds a new invalid parameter error to the collection of invalid // parameters. The context of the invalid parameter will be updated to reflect // this collection. func (e *ErrInvalidParams) Add(err ErrInvalidParam) { err.SetContext(e.Context) e.errs = append(e.errs, err) } // AddNested adds the invalid parameter errors from another ErrInvalidParams // value into this collection. The nested errors will have their nested context // updated and base context to reflect the merging. // // Use for nested validations errors. func (e *ErrInvalidParams) AddNested(nestedCtx string, nested ErrInvalidParams) { for _, err := range nested.errs { err.SetContext(e.Context) err.AddNestedContext(nestedCtx) e.errs = append(e.errs, err) } } // Len returns the number of invalid parameter errors func (e ErrInvalidParams) Len() int { return len(e.errs) } // Code returns the code of the error func (e ErrInvalidParams) Code() string { return InvalidParameterErrCode } // Message returns the message of the error func (e ErrInvalidParams) Message() string { return fmt.Sprintf("%d validation error(s) found.", len(e.errs)) } // Error returns the string formatted form of the invalid parameters. func (e ErrInvalidParams) Error() string { w := &bytes.Buffer{} fmt.Fprintf(w, "%s: %s\n", e.Code(), e.Message()) for _, err := range e.errs { fmt.Fprintf(w, "- %s\n", err.Message()) } return w.String() } // OrigErr returns the invalid parameters as a awserr.BatchedErrors value func (e ErrInvalidParams) OrigErr() error { return awserr.NewBatchError( InvalidParameterErrCode, e.Message(), e.OrigErrs()) } // OrigErrs returns a slice of the invalid parameters func (e ErrInvalidParams) OrigErrs() []error { errs := make([]error, len(e.errs)) for i := 0; i < len(errs); i++ { errs[i] = e.errs[i] } return errs } // An ErrInvalidParam represents an invalid parameter error type. type ErrInvalidParam interface { awserr.Error // Field name the error occurred on. Field() string // SetContext updates the context of the error. SetContext(string) // AddNestedContext updates the error's context to include a nested level. AddNestedContext(string) } type errInvalidParam struct { context string nestedContext string field string code string msg string } // Code returns the error code for the type of invalid parameter. func (e *errInvalidParam) Code() string { return e.code } // Message returns the reason the parameter was invalid, and its context. func (e *errInvalidParam) Message() string { return fmt.Sprintf("%s, %s.", e.msg, e.Field()) } // Error returns the string version of the invalid parameter error. func (e *errInvalidParam) Error() string { return fmt.Sprintf("%s: %s", e.code, e.Message()) } // OrigErr returns nil, Implemented for awserr.Error interface. func (e *errInvalidParam) OrigErr() error { return nil } // Field Returns the field and context the error occurred. func (e *errInvalidParam) Field() string { field := e.context if len(field) > 0 { field += "." } if len(e.nestedContext) > 0 { field += fmt.Sprintf("%s.", e.nestedContext) } field += e.field return field } // SetContext updates the base context of the error. func (e *errInvalidParam) SetContext(ctx string) { e.context = ctx } // AddNestedContext prepends a context to the field's path. func (e *errInvalidParam) AddNestedContext(ctx string) { if len(e.nestedContext) == 0 { e.nestedContext = ctx } else { e.nestedContext = fmt.Sprintf("%s.%s", ctx, e.nestedContext) } } // An ErrParamRequired represents an required parameter error. type ErrParamRequired struct { errInvalidParam } // NewErrParamRequired creates a new required parameter error. func NewErrParamRequired(field string) *ErrParamRequired { return &ErrParamRequired{ errInvalidParam{ code: ParamRequiredErrCode, field: field, msg: fmt.Sprintf("missing required field"), }, } } // An ErrParamMinValue represents a minimum value parameter error. type ErrParamMinValue struct { errInvalidParam min float64 } // NewErrParamMinValue creates a new minimum value parameter error. func NewErrParamMinValue(field string, min float64) *ErrParamMinValue { return &ErrParamMinValue{ errInvalidParam: errInvalidParam{ code: ParamMinValueErrCode, field: field, msg: fmt.Sprintf("minimum field value of %v", min), }, min: min, } } // MinValue returns the field's require minimum value. // // float64 is returned for both int and float min values. func (e *ErrParamMinValue) MinValue() float64 { return e.min } // An ErrParamMinLen represents a minimum length parameter error. type ErrParamMinLen struct { errInvalidParam min int } // NewErrParamMinLen creates a new minimum length parameter error. func NewErrParamMinLen(field string, min int) *ErrParamMinLen { return &ErrParamMinLen{ errInvalidParam: errInvalidParam{ code: ParamMinValueErrCode, field: field, msg: fmt.Sprintf("minimum field size of %v", min), }, min: min, } } // MinLen returns the field's required minimum length. func (e *ErrParamMinLen) MinLen() int { return e.min } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/session/doc.go ================================================ /* Package session provides configuration for the SDK's service clients. Sessions can be shared across all service clients that share the same base configuration. The Session is built from the SDK's default configuration and request handlers. Sessions should be cached when possible, because creating a new Session will load all configuration values from the environment, and config files each time the Session is created. Sharing the Session value across all of your service clients will ensure the configuration is loaded the fewest number of times possible. Concurrency Sessions are safe to use concurrently as long as the Session is not being modified. The SDK will not modify the Session once the Session has been created. Creating service clients concurrently from a shared Session is safe. Sessions from Shared Config Sessions can be created using the method above that will only load the additional config if the AWS_SDK_LOAD_CONFIG environment variable is set. Alternatively you can explicitly create a Session with shared config enabled. To do this you can use NewSessionWithOptions to configure how the Session will be created. Using the NewSessionWithOptions with SharedConfigState set to SharedConfigEnabled will create the session as if the AWS_SDK_LOAD_CONFIG environment variable was set. Creating Sessions When creating Sessions optional aws.Config values can be passed in that will override the default, or loaded config values the Session is being created with. This allows you to provide additional, or case based, configuration as needed. By default NewSession will only load credentials from the shared credentials file (~/.aws/credentials). If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value the Session will be created from the configuration values from the shared config (~/.aws/config) and shared credentials (~/.aws/credentials) files. See the section Sessions from Shared Config for more information. Create a Session with the default config and request handlers. With credentials region, and profile loaded from the environment and shared config automatically. Requires the AWS_PROFILE to be set, or "default" is used. // Create Session sess, err := session.NewSession() // Create a Session with a custom region sess, err := session.NewSession(&aws.Config{Region: aws.String("us-east-1")}) // Create a S3 client instance from a session sess, err := session.NewSession() if err != nil { // Handle Session creation error } svc := s3.New(sess) Create Session With Option Overrides In addition to NewSession, Sessions can be created using NewSessionWithOptions. This func allows you to control and override how the Session will be created through code instead of being driven by environment variables only. Use NewSessionWithOptions when you want to provide the config profile, or override the shared config state (AWS_SDK_LOAD_CONFIG). // Equivalent to session.New sess, err := session.NewSessionWithOptions(session.Options{}) // Specify profile to load for the session's config sess, err := session.NewSessionWithOptions(session.Options{ Profile: "profile_name", }) // Specify profile for config and region for requests sess, err := session.NewSessionWithOptions(session.Options{ Config: aws.Config{Region: aws.String("us-east-1")}, Profile: "profile_name", }) // Force enable Shared Config support sess, err := session.NewSessionWithOptions(session.Options{ SharedConfigState: SharedConfigEnable, }) Adding Handlers You can add handlers to a session for processing HTTP requests. All service clients that use the session inherit the handlers. For example, the following handler logs every request and its payload made by a service client: // Create a session, and add additional handlers for all service // clients created with the Session to inherit. Adds logging handler. sess, err := session.NewSession() sess.Handlers.Send.PushFront(func(r *request.Request) { // Log every request made and its payload logger.Println("Request: %s/%s, Payload: %s", r.ClientInfo.ServiceName, r.Operation, r.Params) }) Deprecated "New" function The New session function has been deprecated because it does not provide good way to return errors that occur when loading the configuration files and values. Because of this, NewSession was created so errors can be retrieved when creating a session fails. Shared Config Fields By default the SDK will only load the shared credentials file's (~/.aws/credentials) credentials values, and all other config is provided by the environment variables, SDK defaults, and user provided aws.Config values. If the AWS_SDK_LOAD_CONFIG environment variable is set, or SharedConfigEnable option is used to create the Session the full shared config values will be loaded. This includes credentials, region, and support for assume role. In addition the Session will load its configuration from both the shared config file (~/.aws/config) and shared credentials file (~/.aws/credentials). Both files have the same format. If both config files are present the configuration from both files will be read. The Session will be created from configuration values from the shared credentials file (~/.aws/credentials) over those in the shared credentials file (~/.aws/config). Credentials are the values the SDK should use for authenticating requests with AWS Services. They arfrom a configuration file will need to include both aws_access_key_id and aws_secret_access_key must be provided together in the same file to be considered valid. The values will be ignored if not a complete group. aws_session_token is an optional field that can be provided if both of the other two fields are also provided. aws_access_key_id = AKID aws_secret_access_key = SECRET aws_session_token = TOKEN Assume Role values allow you to configure the SDK to assume an IAM role using a set of credentials provided in a config file via the source_profile field. Both "role_arn" and "source_profile" are required. The SDK does not support assuming a role with MFA token Via the Session's constructor. You can use the stscreds.AssumeRoleProvider credentials provider to specify custom configuration and support for MFA. role_arn = arn:aws:iam:::role/ source_profile = profile_with_creds external_id = 1234 mfa_serial = not supported! role_session_name = session_name Region is the region the SDK should use for looking up AWS service endpoints and signing requests. region = us-east-1 Environment Variables When a Session is created several environment variables can be set to adjust how the SDK functions, and what configuration data it loads when creating Sessions. All environment values are optional, but some values like credentials require multiple of the values to set or the partial values will be ignored. All environment variable values are strings unless otherwise noted. Environment configuration values. If set both Access Key ID and Secret Access Key must be provided. Session Token and optionally also be provided, but is not required. # Access Key ID AWS_ACCESS_KEY_ID=AKID AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set. # Secret Access Key AWS_SECRET_ACCESS_KEY=SECRET AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set. # Session Token AWS_SESSION_TOKEN=TOKEN Region value will instruct the SDK where to make service API requests to. If is not provided in the environment the region must be provided before a service client request is made. AWS_REGION=us-east-1 # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set, # and AWS_REGION is not also set. AWS_DEFAULT_REGION=us-east-1 Profile name the SDK should load use when loading shared config from the configuration files. If not provided "default" will be used as the profile name. AWS_PROFILE=my_profile # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set, # and AWS_PROFILE is not also set. AWS_DEFAULT_PROFILE=my_profile SDK load config instructs the SDK to load the shared config in addition to shared credentials. This also expands the configuration loaded so the shared credentials will have parity with the shared config file. This also enables Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE env values as well. AWS_SDK_LOAD_CONFIG=1 Shared credentials file path can be set to instruct the SDK to use an alternative file for the shared credentials. If not set the file will be loaded from $HOME/.aws/credentials on Linux/Unix based systems, and %USERPROFILE%\.aws\credentials on Windows. AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials Shared config file path can be set to instruct the SDK to use an alternative file for the shared config. If not set the file will be loaded from $HOME/.aws/config on Linux/Unix based systems, and %USERPROFILE%\.aws\config on Windows. AWS_CONFIG_FILE=$HOME/my_shared_config */ package session ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/session/env_config.go ================================================ package session import ( "os" "path/filepath" "strconv" "github.com/aws/aws-sdk-go/aws/credentials" ) // envConfig is a collection of environment values the SDK will read // setup config from. All environment values are optional. But some values // such as credentials require multiple values to be complete or the values // will be ignored. type envConfig struct { // Environment configuration values. If set both Access Key ID and Secret Access // Key must be provided. Session Token and optionally also be provided, but is // not required. // // # Access Key ID // AWS_ACCESS_KEY_ID=AKID // AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set. // // # Secret Access Key // AWS_SECRET_ACCESS_KEY=SECRET // AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set. // // # Session Token // AWS_SESSION_TOKEN=TOKEN Creds credentials.Value // Region value will instruct the SDK where to make service API requests to. If is // not provided in the environment the region must be provided before a service // client request is made. // // AWS_REGION=us-east-1 // // # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set, // # and AWS_REGION is not also set. // AWS_DEFAULT_REGION=us-east-1 Region string // Profile name the SDK should load use when loading shared configuration from the // shared configuration files. If not provided "default" will be used as the // profile name. // // AWS_PROFILE=my_profile // // # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set, // # and AWS_PROFILE is not also set. // AWS_DEFAULT_PROFILE=my_profile Profile string // SDK load config instructs the SDK to load the shared config in addition to // shared credentials. This also expands the configuration loaded from the shared // credentials to have parity with the shared config file. This also enables // Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE // env values as well. // // AWS_SDK_LOAD_CONFIG=1 EnableSharedConfig bool // Shared credentials file path can be set to instruct the SDK to use an alternate // file for the shared credentials. If not set the file will be loaded from // $HOME/.aws/credentials on Linux/Unix based systems, and // %USERPROFILE%\.aws\credentials on Windows. // // AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials SharedCredentialsFile string // Shared config file path can be set to instruct the SDK to use an alternate // file for the shared config. If not set the file will be loaded from // $HOME/.aws/config on Linux/Unix based systems, and // %USERPROFILE%\.aws\config on Windows. // // AWS_CONFIG_FILE=$HOME/my_shared_config SharedConfigFile string } var ( credAccessEnvKey = []string{ "AWS_ACCESS_KEY_ID", "AWS_ACCESS_KEY", } credSecretEnvKey = []string{ "AWS_SECRET_ACCESS_KEY", "AWS_SECRET_KEY", } credSessionEnvKey = []string{ "AWS_SESSION_TOKEN", } regionEnvKeys = []string{ "AWS_REGION", "AWS_DEFAULT_REGION", // Only read if AWS_SDK_LOAD_CONFIG is also set } profileEnvKeys = []string{ "AWS_PROFILE", "AWS_DEFAULT_PROFILE", // Only read if AWS_SDK_LOAD_CONFIG is also set } ) // loadEnvConfig retrieves the SDK's environment configuration. // See `envConfig` for the values that will be retrieved. // // If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value // the shared SDK config will be loaded in addition to the SDK's specific // configuration values. func loadEnvConfig() envConfig { enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG")) return envConfigLoad(enableSharedConfig) } // loadEnvSharedConfig retrieves the SDK's environment configuration, and the // SDK shared config. See `envConfig` for the values that will be retrieved. // // Loads the shared configuration in addition to the SDK's specific configuration. // This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG` // environment variable is set. func loadSharedEnvConfig() envConfig { return envConfigLoad(true) } func envConfigLoad(enableSharedConfig bool) envConfig { cfg := envConfig{} cfg.EnableSharedConfig = enableSharedConfig setFromEnvVal(&cfg.Creds.AccessKeyID, credAccessEnvKey) setFromEnvVal(&cfg.Creds.SecretAccessKey, credSecretEnvKey) setFromEnvVal(&cfg.Creds.SessionToken, credSessionEnvKey) // Require logical grouping of credentials if len(cfg.Creds.AccessKeyID) == 0 || len(cfg.Creds.SecretAccessKey) == 0 { cfg.Creds = credentials.Value{} } else { cfg.Creds.ProviderName = "EnvConfigCredentials" } regionKeys := regionEnvKeys profileKeys := profileEnvKeys if !cfg.EnableSharedConfig { regionKeys = regionKeys[:1] profileKeys = profileKeys[:1] } setFromEnvVal(&cfg.Region, regionKeys) setFromEnvVal(&cfg.Profile, profileKeys) cfg.SharedCredentialsFile = sharedCredentialsFilename() cfg.SharedConfigFile = sharedConfigFilename() return cfg } func setFromEnvVal(dst *string, keys []string) { for _, k := range keys { if v := os.Getenv(k); len(v) > 0 { *dst = v break } } } func sharedCredentialsFilename() string { if name := os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(name) > 0 { return name } return filepath.Join(userHomeDir(), ".aws", "credentials") } func sharedConfigFilename() string { if name := os.Getenv("AWS_CONFIG_FILE"); len(name) > 0 { return name } return filepath.Join(userHomeDir(), ".aws", "config") } func userHomeDir() string { homeDir := os.Getenv("HOME") // *nix if len(homeDir) == 0 { // windows homeDir = os.Getenv("USERPROFILE") } return homeDir } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/session/session.go ================================================ package session import ( "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/corehandlers" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/stscreds" "github.com/aws/aws-sdk-go/aws/defaults" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/private/endpoints" ) // A Session provides a central location to create service clients from and // store configurations and request handlers for those services. // // Sessions are safe to create service clients concurrently, but it is not safe // to mutate the Session concurrently. // // The Session satisfies the service client's client.ClientConfigProvider. type Session struct { Config *aws.Config Handlers request.Handlers } // New creates a new instance of the handlers merging in the provided configs // on top of the SDK's default configurations. Once the Session is created it // can be mutated to modify the Config or Handlers. The Session is safe to be // read concurrently, but it should not be written to concurrently. // // If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New // method could now encounter an error when loading the configuration. When // The environment variable is set, and an error occurs, New will return a // session that will fail all requests reporting the error that occured while // loading the session. Use NewSession to get the error when creating the // session. // // If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value // the shared config file (~/.aws/config) will also be loaded, in addition to // the shared credentials file (~/.aws/config). Values set in both the // shared config, and shared credentials will be taken from the shared // credentials file. // // Deprecated: Use NewSession functiions to create sessions instead. NewSession // has the same functionality as New except an error can be returned when the // func is called instead of waiting to receive an error until a request is made. func New(cfgs ...*aws.Config) *Session { // load initial config from environment envCfg := loadEnvConfig() if envCfg.EnableSharedConfig { s, err := newSession(envCfg, cfgs...) if err != nil { // Old session.New expected all errors to be discovered when // a request is made, and would report the errors then. This // needs to be replicated if an error occurs while creating // the session. msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " + "Use session.NewSession to handle errors occuring during session creation." // Session creation failed, need to report the error and prevent // any requests from succeeding. s = &Session{Config: defaults.Config()} s.Config.MergeIn(cfgs...) s.Config.Logger.Log("ERROR:", msg, "Error:", err) s.Handlers.Validate.PushBack(func(r *request.Request) { r.Error = err }) } return s } return oldNewSession(cfgs...) } // NewSession returns a new Session created from SDK defaults, config files, // environment, and user provided config files. Once the Session is created // it can be mutated to modify the Config or Handlers. The Session is safe to // be read concurrently, but it should not be written to concurrently. // // If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value // the shared config file (~/.aws/config) will also be loaded in addition to // the shared credentials file (~/.aws/config). Values set in both the // shared config, and shared credentials will be taken from the shared // credentials file. Enabling the Shared Config will also allow the Session // to be built with retrieving credentials with AssumeRole set in the config. // // See the NewSessionWithOptions func for information on how to override or // control through code how the Session will be created. Such as specifing the // config profile, and controlling if shared config is enabled or not. func NewSession(cfgs ...*aws.Config) (*Session, error) { envCfg := loadEnvConfig() return newSession(envCfg, cfgs...) } // SharedConfigState provides the ability to optionally override the state // of the session's creation based on the shared config being enabled or // disabled. type SharedConfigState int const ( // SharedConfigStateFromEnv does not override any state of the // AWS_SDK_LOAD_CONFIG env var. It is the default value of the // SharedConfigState type. SharedConfigStateFromEnv SharedConfigState = iota // SharedConfigDisable overrides the AWS_SDK_LOAD_CONFIG env var value // and disables the shared config functionality. SharedConfigDisable // SharedConfigEnable overrides the AWS_SDK_LOAD_CONFIG env var value // and enables the shared config functionality. SharedConfigEnable ) // Options provides the means to control how a Session is created and what // configuration values will be loaded. // type Options struct { // Provides config values for the SDK to use when creating service clients // and making API requests to services. Any value set in with this field // will override the associated value provided by the SDK defaults, // environment or config files where relevent. // // If not set, configuration values from from SDK defaults, environment, // config will be used. Config aws.Config // Overrides the config profile the Session should be created from. If not // set the value of the environment variable will be loaded (AWS_PROFILE, // or AWS_DEFAULT_PROFILE if the Shared Config is enabled). // // If not set and environment variables are not set the "default" // (DefaultSharedConfigProfile) will be used as the profile to load the // session config from. Profile string // Instructs how the Session will be created based on the AWS_SDK_LOAD_CONFIG // environment variable. By default a Session will be created using the // value provided by the AWS_SDK_LOAD_CONFIG environment variable. // // Setting this value to SharedConfigEnable or SharedConfigDisable // will allow you to override the AWS_SDK_LOAD_CONFIG environment variable // and enable or disable the shared config functionality. SharedConfigState SharedConfigState } // NewSessionWithOptions returns a new Session created from SDK defaults, config files, // environment, and user provided config files. This func uses the Options // values to configure how the Session is created. // // If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value // the shared config file (~/.aws/config) will also be loaded in addition to // the shared credentials file (~/.aws/config). Values set in both the // shared config, and shared credentials will be taken from the shared // credentials file. Enabling the Shared Config will also allow the Session // to be built with retrieving credentials with AssumeRole set in the config. // // // Equivalent to session.New // sess, err := session.NewSessionWithOptions(session.Options{}) // // // Specify profile to load for the session's config // sess, err := session.NewSessionWithOptions(session.Options{ // Profile: "profile_name", // }) // // // Specify profile for config and region for requests // sess, err := session.NewSessionWithOptions(session.Options{ // Config: aws.Config{Region: aws.String("us-east-1")}, // Profile: "profile_name", // }) // // // Force enable Shared Config support // sess, err := session.NewSessionWithOptions(session.Options{ // SharedConfigState: SharedConfigEnable, // }) func NewSessionWithOptions(opts Options) (*Session, error) { envCfg := loadEnvConfig() if len(opts.Profile) > 0 { envCfg.Profile = opts.Profile } switch opts.SharedConfigState { case SharedConfigDisable: envCfg.EnableSharedConfig = false case SharedConfigEnable: envCfg.EnableSharedConfig = true } return newSession(envCfg, &opts.Config) } // Must is a helper function to ensure the Session is valid and there was no // error when calling a NewSession function. // // This helper is intended to be used in variable initialization to load the // Session and configuration at startup. Such as: // // var sess = session.Must(session.NewSession()) func Must(sess *Session, err error) *Session { if err != nil { panic(err) } return sess } func oldNewSession(cfgs ...*aws.Config) *Session { cfg := defaults.Config() handlers := defaults.Handlers() // Apply the passed in configs so the configuration can be applied to the // default credential chain cfg.MergeIn(cfgs...) cfg.Credentials = defaults.CredChain(cfg, handlers) // Reapply any passed in configs to override credentials if set cfg.MergeIn(cfgs...) s := &Session{ Config: cfg, Handlers: handlers, } initHandlers(s) return s } func newSession(envCfg envConfig, cfgs ...*aws.Config) (*Session, error) { cfg := defaults.Config() handlers := defaults.Handlers() // Get a merged version of the user provided config to determine if // credentials were. userCfg := &aws.Config{} userCfg.MergeIn(cfgs...) // Order config files will be loaded in with later files overwriting // previous config file values. cfgFiles := []string{envCfg.SharedConfigFile, envCfg.SharedCredentialsFile} if !envCfg.EnableSharedConfig { // The shared config file (~/.aws/config) is only loaded if instructed // to load via the envConfig.EnableSharedConfig (AWS_SDK_LOAD_CONFIG). cfgFiles = cfgFiles[1:] } // Load additional config from file(s) sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles) if err != nil { return nil, err } mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers) s := &Session{ Config: cfg, Handlers: handlers, } initHandlers(s) return s, nil } func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers) { // Merge in user provided configuration cfg.MergeIn(userCfg) // Region if not already set by user if len(aws.StringValue(cfg.Region)) == 0 { if len(envCfg.Region) > 0 { cfg.WithRegion(envCfg.Region) } else if envCfg.EnableSharedConfig && len(sharedCfg.Region) > 0 { cfg.WithRegion(sharedCfg.Region) } } // Configure credentials if not already set if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil { if len(envCfg.Creds.AccessKeyID) > 0 { cfg.Credentials = credentials.NewStaticCredentialsFromCreds( envCfg.Creds, ) } else if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.RoleARN) > 0 && sharedCfg.AssumeRoleSource != nil { cfgCp := *cfg cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds( sharedCfg.AssumeRoleSource.Creds, ) cfg.Credentials = stscreds.NewCredentials( &Session{ Config: &cfgCp, Handlers: handlers.Copy(), }, sharedCfg.AssumeRole.RoleARN, func(opt *stscreds.AssumeRoleProvider) { opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName if len(sharedCfg.AssumeRole.ExternalID) > 0 { opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID) } // MFA not supported }, ) } else if len(sharedCfg.Creds.AccessKeyID) > 0 { cfg.Credentials = credentials.NewStaticCredentialsFromCreds( sharedCfg.Creds, ) } else { // Fallback to default credentials provider, include mock errors // for the credential chain so user can identify why credentials // failed to be retrieved. cfg.Credentials = credentials.NewCredentials(&credentials.ChainProvider{ VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors), Providers: []credentials.Provider{ &credProviderError{Err: awserr.New("EnvAccessKeyNotFound", "failed to find credentials in the environment.", nil)}, &credProviderError{Err: awserr.New("SharedCredsLoad", fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil)}, defaults.RemoteCredProvider(*cfg, handlers), }, }) } } } type credProviderError struct { Err error } var emptyCreds = credentials.Value{} func (c credProviderError) Retrieve() (credentials.Value, error) { return credentials.Value{}, c.Err } func (c credProviderError) IsExpired() bool { return true } func initHandlers(s *Session) { // Add the Validate parameter handler if it is not disabled. s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler) if !aws.BoolValue(s.Config.DisableParamValidation) { s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler) } } // Copy creates and returns a copy of the current Session, coping the config // and handlers. If any additional configs are provided they will be merged // on top of the Session's copied config. // // // Create a copy of the current Session, configured for the us-west-2 region. // sess.Copy(&aws.Config{Region: aws.String("us-west-2")}) func (s *Session) Copy(cfgs ...*aws.Config) *Session { newSession := &Session{ Config: s.Config.Copy(cfgs...), Handlers: s.Handlers.Copy(), } initHandlers(newSession) return newSession } // ClientConfig satisfies the client.ConfigProvider interface and is used to // configure the service client instances. Passing the Session to the service // client's constructor (New) will use this method to configure the client. func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config { s = s.Copy(cfgs...) endpoint, signingRegion := endpoints.NormalizeEndpoint( aws.StringValue(s.Config.Endpoint), serviceName, aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL), aws.BoolValue(s.Config.UseDualStack), ) return client.Config{ Config: s.Config, Handlers: s.Handlers, Endpoint: endpoint, SigningRegion: signingRegion, } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go ================================================ package session import ( "fmt" "os" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/go-ini/ini" ) const ( // Static Credentials group accessKeyIDKey = `aws_access_key_id` // group required secretAccessKey = `aws_secret_access_key` // group required sessionTokenKey = `aws_session_token` // optional // Assume Role Credentials group roleArnKey = `role_arn` // group required sourceProfileKey = `source_profile` // group required externalIDKey = `external_id` // optional mfaSerialKey = `mfa_serial` // optional roleSessionNameKey = `role_session_name` // optional // Additional Config fields regionKey = `region` // DefaultSharedConfigProfile is the default profile to be used when // loading configuration from the config files if another profile name // is not provided. DefaultSharedConfigProfile = `default` ) type assumeRoleConfig struct { RoleARN string SourceProfile string ExternalID string MFASerial string RoleSessionName string } // sharedConfig represents the configuration fields of the SDK config files. type sharedConfig struct { // Credentials values from the config file. Both aws_access_key_id // and aws_secret_access_key must be provided together in the same file // to be considered valid. The values will be ignored if not a complete group. // aws_session_token is an optional field that can be provided if both of the // other two fields are also provided. // // aws_access_key_id // aws_secret_access_key // aws_session_token Creds credentials.Value AssumeRole assumeRoleConfig AssumeRoleSource *sharedConfig // Region is the region the SDK should use for looking up AWS service endpoints // and signing requests. // // region Region string } type sharedConfigFile struct { Filename string IniData *ini.File } // loadSharedConfig retrieves the configuration from the list of files // using the profile provided. The order the files are listed will determine // precedence. Values in subsequent files will overwrite values defined in // earlier files. // // For example, given two files A and B. Both define credentials. If the order // of the files are A then B, B's credential values will be used instead of A's. // // See sharedConfig.setFromFile for information how the config files // will be loaded. func loadSharedConfig(profile string, filenames []string) (sharedConfig, error) { if len(profile) == 0 { profile = DefaultSharedConfigProfile } files, err := loadSharedConfigIniFiles(filenames) if err != nil { return sharedConfig{}, err } cfg := sharedConfig{} if err = cfg.setFromIniFiles(profile, files); err != nil { return sharedConfig{}, err } if len(cfg.AssumeRole.SourceProfile) > 0 { if err := cfg.setAssumeRoleSource(profile, files); err != nil { return sharedConfig{}, err } } return cfg, nil } func loadSharedConfigIniFiles(filenames []string) ([]sharedConfigFile, error) { files := make([]sharedConfigFile, 0, len(filenames)) for _, filename := range filenames { if _, err := os.Stat(filename); os.IsNotExist(err) { // Trim files from the list that don't exist. continue } f, err := ini.Load(filename) if err != nil { return nil, SharedConfigLoadError{Filename: filename} } files = append(files, sharedConfigFile{ Filename: filename, IniData: f, }) } return files, nil } func (cfg *sharedConfig) setAssumeRoleSource(origProfile string, files []sharedConfigFile) error { var assumeRoleSrc sharedConfig // Multiple level assume role chains are not support if cfg.AssumeRole.SourceProfile == origProfile { assumeRoleSrc = *cfg assumeRoleSrc.AssumeRole = assumeRoleConfig{} } else { err := assumeRoleSrc.setFromIniFiles(cfg.AssumeRole.SourceProfile, files) if err != nil { return err } } if len(assumeRoleSrc.Creds.AccessKeyID) == 0 { return SharedConfigAssumeRoleError{RoleARN: cfg.AssumeRole.RoleARN} } cfg.AssumeRoleSource = &assumeRoleSrc return nil } func (cfg *sharedConfig) setFromIniFiles(profile string, files []sharedConfigFile) error { // Trim files from the list that don't exist. for _, f := range files { if err := cfg.setFromIniFile(profile, f); err != nil { if _, ok := err.(SharedConfigProfileNotExistsError); ok { // Ignore proviles missings continue } return err } } return nil } // setFromFile loads the configuration from the file using // the profile provided. A sharedConfig pointer type value is used so that // multiple config file loadings can be chained. // // Only loads complete logically grouped values, and will not set fields in cfg // for incomplete grouped values in the config. Such as credentials. For example // if a config file only includes aws_access_key_id but no aws_secret_access_key // the aws_access_key_id will be ignored. func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile) error { section, err := file.IniData.GetSection(profile) if err != nil { // Fallback to to alternate profile name: profile section, err = file.IniData.GetSection(fmt.Sprintf("profile %s", profile)) if err != nil { return SharedConfigProfileNotExistsError{Profile: profile, Err: err} } } // Shared Credentials akid := section.Key(accessKeyIDKey).String() secret := section.Key(secretAccessKey).String() if len(akid) > 0 && len(secret) > 0 { cfg.Creds = credentials.Value{ AccessKeyID: akid, SecretAccessKey: secret, SessionToken: section.Key(sessionTokenKey).String(), ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", file.Filename), } } // Assume Role roleArn := section.Key(roleArnKey).String() srcProfile := section.Key(sourceProfileKey).String() if len(roleArn) > 0 && len(srcProfile) > 0 { cfg.AssumeRole = assumeRoleConfig{ RoleARN: roleArn, SourceProfile: srcProfile, ExternalID: section.Key(externalIDKey).String(), MFASerial: section.Key(mfaSerialKey).String(), RoleSessionName: section.Key(roleSessionNameKey).String(), } } // Region if v := section.Key(regionKey).String(); len(v) > 0 { cfg.Region = v } return nil } // SharedConfigLoadError is an error for the shared config file failed to load. type SharedConfigLoadError struct { Filename string Err error } // Code is the short id of the error. func (e SharedConfigLoadError) Code() string { return "SharedConfigLoadError" } // Message is the description of the error func (e SharedConfigLoadError) Message() string { return fmt.Sprintf("failed to load config file, %s", e.Filename) } // OrigErr is the underlying error that caused the failure. func (e SharedConfigLoadError) OrigErr() error { return e.Err } // Error satisfies the error interface. func (e SharedConfigLoadError) Error() string { return awserr.SprintError(e.Code(), e.Message(), "", e.Err) } // SharedConfigProfileNotExistsError is an error for the shared config when // the profile was not find in the config file. type SharedConfigProfileNotExistsError struct { Profile string Err error } // Code is the short id of the error. func (e SharedConfigProfileNotExistsError) Code() string { return "SharedConfigProfileNotExistsError" } // Message is the description of the error func (e SharedConfigProfileNotExistsError) Message() string { return fmt.Sprintf("failed to get profile, %s", e.Profile) } // OrigErr is the underlying error that caused the failure. func (e SharedConfigProfileNotExistsError) OrigErr() error { return e.Err } // Error satisfies the error interface. func (e SharedConfigProfileNotExistsError) Error() string { return awserr.SprintError(e.Code(), e.Message(), "", e.Err) } // SharedConfigAssumeRoleError is an error for the shared config when the // profile contains assume role information, but that information is invalid // or not complete. type SharedConfigAssumeRoleError struct { RoleARN string } // Code is the short id of the error. func (e SharedConfigAssumeRoleError) Code() string { return "SharedConfigAssumeRoleError" } // Message is the description of the error func (e SharedConfigAssumeRoleError) Message() string { return fmt.Sprintf("failed to load assume role for %s, source profile has no shared credentials", e.RoleARN) } // OrigErr is the underlying error that caused the failure. func (e SharedConfigAssumeRoleError) OrigErr() error { return nil } // Error satisfies the error interface. func (e SharedConfigAssumeRoleError) Error() string { return awserr.SprintError(e.Code(), e.Message(), "", nil) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go ================================================ package v4 import ( "net/http" "strings" ) // validator houses a set of rule needed for validation of a // string value type rules []rule // rule interface allows for more flexible rules and just simply // checks whether or not a value adheres to that rule type rule interface { IsValid(value string) bool } // IsValid will iterate through all rules and see if any rules // apply to the value and supports nested rules func (r rules) IsValid(value string) bool { for _, rule := range r { if rule.IsValid(value) { return true } } return false } // mapRule generic rule for maps type mapRule map[string]struct{} // IsValid for the map rule satisfies whether it exists in the map func (m mapRule) IsValid(value string) bool { _, ok := m[value] return ok } // whitelist is a generic rule for whitelisting type whitelist struct { rule } // IsValid for whitelist checks if the value is within the whitelist func (w whitelist) IsValid(value string) bool { return w.rule.IsValid(value) } // blacklist is a generic rule for blacklisting type blacklist struct { rule } // IsValid for whitelist checks if the value is within the whitelist func (b blacklist) IsValid(value string) bool { return !b.rule.IsValid(value) } type patterns []string // IsValid for patterns checks each pattern and returns if a match has // been found func (p patterns) IsValid(value string) bool { for _, pattern := range p { if strings.HasPrefix(http.CanonicalHeaderKey(value), pattern) { return true } } return false } // inclusiveRules rules allow for rules to depend on one another type inclusiveRules []rule // IsValid will return true if all rules are true func (r inclusiveRules) IsValid(value string) bool { for _, rule := range r { if !rule.IsValid(value) { return false } } return true } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go ================================================ // Package v4 implements signing for AWS V4 signer // // Provides request signing for request that need to be signed with // AWS V4 Signatures. package v4 import ( "bytes" "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "io" "net/http" "net/url" "sort" "strconv" "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/private/protocol/rest" ) const ( authHeaderPrefix = "AWS4-HMAC-SHA256" timeFormat = "20060102T150405Z" shortTimeFormat = "20060102" // emptyStringSHA256 is a SHA256 of an empty string emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855` ) var ignoredHeaders = rules{ blacklist{ mapRule{ "Authorization": struct{}{}, "User-Agent": struct{}{}, }, }, } // requiredSignedHeaders is a whitelist for build canonical headers. var requiredSignedHeaders = rules{ whitelist{ mapRule{ "Cache-Control": struct{}{}, "Content-Disposition": struct{}{}, "Content-Encoding": struct{}{}, "Content-Language": struct{}{}, "Content-Md5": struct{}{}, "Content-Type": struct{}{}, "Expires": struct{}{}, "If-Match": struct{}{}, "If-Modified-Since": struct{}{}, "If-None-Match": struct{}{}, "If-Unmodified-Since": struct{}{}, "Range": struct{}{}, "X-Amz-Acl": struct{}{}, "X-Amz-Copy-Source": struct{}{}, "X-Amz-Copy-Source-If-Match": struct{}{}, "X-Amz-Copy-Source-If-Modified-Since": struct{}{}, "X-Amz-Copy-Source-If-None-Match": struct{}{}, "X-Amz-Copy-Source-If-Unmodified-Since": struct{}{}, "X-Amz-Copy-Source-Range": struct{}{}, "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": struct{}{}, "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": struct{}{}, "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5": struct{}{}, "X-Amz-Grant-Full-control": struct{}{}, "X-Amz-Grant-Read": struct{}{}, "X-Amz-Grant-Read-Acp": struct{}{}, "X-Amz-Grant-Write": struct{}{}, "X-Amz-Grant-Write-Acp": struct{}{}, "X-Amz-Metadata-Directive": struct{}{}, "X-Amz-Mfa": struct{}{}, "X-Amz-Request-Payer": struct{}{}, "X-Amz-Server-Side-Encryption": struct{}{}, "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": struct{}{}, "X-Amz-Server-Side-Encryption-Customer-Algorithm": struct{}{}, "X-Amz-Server-Side-Encryption-Customer-Key": struct{}{}, "X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{}, "X-Amz-Storage-Class": struct{}{}, "X-Amz-Website-Redirect-Location": struct{}{}, }, }, patterns{"X-Amz-Meta-"}, } // allowedHoisting is a whitelist for build query headers. The boolean value // represents whether or not it is a pattern. var allowedQueryHoisting = inclusiveRules{ blacklist{requiredSignedHeaders}, patterns{"X-Amz-"}, } // Signer applies AWS v4 signing to given request. Use this to sign requests // that need to be signed with AWS V4 Signatures. type Signer struct { // The authentication credentials the request will be signed against. // This value must be set to sign requests. Credentials *credentials.Credentials // Sets the log level the signer should use when reporting information to // the logger. If the logger is nil nothing will be logged. See // aws.LogLevelType for more information on available logging levels // // By default nothing will be logged. Debug aws.LogLevelType // The logger loging information will be written to. If there the logger // is nil, nothing will be logged. Logger aws.Logger // Disables the Signer's moving HTTP header key/value pairs from the HTTP // request header to the request's query string. This is most commonly used // with pre-signed requests preventing headers from being added to the // request's query string. DisableHeaderHoisting bool // currentTimeFn returns the time value which represents the current time. // This value should only be used for testing. If it is nil the default // time.Now will be used. currentTimeFn func() time.Time } // NewSigner returns a Signer pointer configured with the credentials and optional // option values provided. If not options are provided the Signer will use its // default configuration. func NewSigner(credentials *credentials.Credentials, options ...func(*Signer)) *Signer { v4 := &Signer{ Credentials: credentials, } for _, option := range options { option(v4) } return v4 } type signingCtx struct { ServiceName string Region string Request *http.Request Body io.ReadSeeker Query url.Values Time time.Time ExpireTime time.Duration SignedHeaderVals http.Header credValues credentials.Value isPresign bool formattedTime string formattedShortTime string bodyDigest string signedHeaders string canonicalHeaders string canonicalString string credentialString string stringToSign string signature string authorization string } // Sign signs AWS v4 requests with the provided body, service name, region the // request is made to, and time the request is signed at. The signTime allows // you to specify that a request is signed for the future, and cannot be // used until then. // // Returns a list of HTTP headers that were included in the signature or an // error if signing the request failed. Generally for signed requests this value // is not needed as the full request context will be captured by the http.Request // value. It is included for reference though. // // Sign differs from Presign in that it will sign the request using HTTP // header values. This type of signing is intended for http.Request values that // will not be shared, or are shared in a way the header values on the request // will not be lost. // // The requests body is an io.ReadSeeker so the SHA256 of the body can be // generated. To bypass the signer computing the hash you can set the // "X-Amz-Content-Sha256" header with a precomputed value. The signer will // only compute the hash if the request header value is empty. func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region string, signTime time.Time) (http.Header, error) { return v4.signWithBody(r, body, service, region, 0, signTime) } // Presign signs AWS v4 requests with the provided body, service name, region // the request is made to, and time the request is signed at. The signTime // allows you to specify that a request is signed for the future, and cannot // be used until then. // // Returns a list of HTTP headers that were included in the signature or an // error if signing the request failed. For presigned requests these headers // and their values must be included on the HTTP request when it is made. This // is helpful to know what header values need to be shared with the party the // presigned request will be distributed to. // // Presign differs from Sign in that it will sign the request using query string // instead of header values. This allows you to share the Presigned Request's // URL with third parties, or distribute it throughout your system with minimal // dependencies. // // Presign also takes an exp value which is the duration the // signed request will be valid after the signing time. This is allows you to // set when the request will expire. // // The requests body is an io.ReadSeeker so the SHA256 of the body can be // generated. To bypass the signer computing the hash you can set the // "X-Amz-Content-Sha256" header with a precomputed value. The signer will // only compute the hash if the request header value is empty. // // Presigning a S3 request will not compute the body's SHA256 hash by default. // This is done due to the general use case for S3 presigned URLs is to share // PUT/GET capabilities. If you would like to include the body's SHA256 in the // presigned request's signature you can set the "X-Amz-Content-Sha256" // HTTP header and that will be included in the request's signature. func (v4 Signer) Presign(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) { return v4.signWithBody(r, body, service, region, exp, signTime) } func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) { currentTimeFn := v4.currentTimeFn if currentTimeFn == nil { currentTimeFn = time.Now } ctx := &signingCtx{ Request: r, Body: body, Query: r.URL.Query(), Time: signTime, ExpireTime: exp, isPresign: exp != 0, ServiceName: service, Region: region, } if ctx.isRequestSigned() { if !v4.Credentials.IsExpired() && currentTimeFn().Before(ctx.Time.Add(10*time.Minute)) { // If the request is already signed, and the credentials have not // expired, and the request is not too old ignore the signing request. return ctx.SignedHeaderVals, nil } ctx.Time = currentTimeFn() ctx.handlePresignRemoval() } var err error ctx.credValues, err = v4.Credentials.Get() if err != nil { return http.Header{}, err } ctx.assignAmzQueryValues() ctx.build(v4.DisableHeaderHoisting) if v4.Debug.Matches(aws.LogDebugWithSigning) { v4.logSigningInfo(ctx) } return ctx.SignedHeaderVals, nil } func (ctx *signingCtx) handlePresignRemoval() { if !ctx.isPresign { return } // The credentials have expired for this request. The current signing // is invalid, and needs to be request because the request will fail. ctx.removePresign() // Update the request's query string to ensure the values stays in // sync in the case retrieving the new credentials fails. ctx.Request.URL.RawQuery = ctx.Query.Encode() } func (ctx *signingCtx) assignAmzQueryValues() { if ctx.isPresign { ctx.Query.Set("X-Amz-Algorithm", authHeaderPrefix) if ctx.credValues.SessionToken != "" { ctx.Query.Set("X-Amz-Security-Token", ctx.credValues.SessionToken) } else { ctx.Query.Del("X-Amz-Security-Token") } return } if ctx.credValues.SessionToken != "" { ctx.Request.Header.Set("X-Amz-Security-Token", ctx.credValues.SessionToken) } } // SignRequestHandler is a named request handler the SDK will use to sign // service client request with using the V4 signature. var SignRequestHandler = request.NamedHandler{ Name: "v4.SignRequestHandler", Fn: SignSDKRequest, } // SignSDKRequest signs an AWS request with the V4 signature. This // request handler is bested used only with the SDK's built in service client's // API operation requests. // // This function should not be used on its on its own, but in conjunction with // an AWS service client's API operation call. To sign a standalone request // not created by a service client's API operation method use the "Sign" or // "Presign" functions of the "Signer" type. // // If the credentials of the request's config are set to // credentials.AnonymousCredentials the request will not be signed. func SignSDKRequest(req *request.Request) { signSDKRequestWithCurrTime(req, time.Now) } func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time) { // If the request does not need to be signed ignore the signing of the // request if the AnonymousCredentials object is used. if req.Config.Credentials == credentials.AnonymousCredentials { return } region := req.ClientInfo.SigningRegion if region == "" { region = aws.StringValue(req.Config.Region) } name := req.ClientInfo.SigningName if name == "" { name = req.ClientInfo.ServiceName } v4 := NewSigner(req.Config.Credentials, func(v4 *Signer) { v4.Debug = req.Config.LogLevel.Value() v4.Logger = req.Config.Logger v4.DisableHeaderHoisting = req.NotHoist v4.currentTimeFn = curTimeFn }) signingTime := req.Time if !req.LastSignedAt.IsZero() { signingTime = req.LastSignedAt } signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.Body, name, region, req.ExpireTime, signingTime) if err != nil { req.Error = err req.SignedHeaderVals = nil return } req.SignedHeaderVals = signedHeaders req.LastSignedAt = curTimeFn() } const logSignInfoMsg = `DEBUG: Request Signiture: ---[ CANONICAL STRING ]----------------------------- %s ---[ STRING TO SIGN ]-------------------------------- %s%s -----------------------------------------------------` const logSignedURLMsg = ` ---[ SIGNED URL ]------------------------------------ %s` func (v4 *Signer) logSigningInfo(ctx *signingCtx) { signedURLMsg := "" if ctx.isPresign { signedURLMsg = fmt.Sprintf(logSignedURLMsg, ctx.Request.URL.String()) } msg := fmt.Sprintf(logSignInfoMsg, ctx.canonicalString, ctx.stringToSign, signedURLMsg) v4.Logger.Log(msg) } func (ctx *signingCtx) build(disableHeaderHoisting bool) { ctx.buildTime() // no depends ctx.buildCredentialString() // no depends unsignedHeaders := ctx.Request.Header if ctx.isPresign { if !disableHeaderHoisting { urlValues := url.Values{} urlValues, unsignedHeaders = buildQuery(allowedQueryHoisting, unsignedHeaders) // no depends for k := range urlValues { ctx.Query[k] = urlValues[k] } } } ctx.buildBodyDigest() ctx.buildCanonicalHeaders(ignoredHeaders, unsignedHeaders) ctx.buildCanonicalString() // depends on canon headers / signed headers ctx.buildStringToSign() // depends on canon string ctx.buildSignature() // depends on string to sign if ctx.isPresign { ctx.Request.URL.RawQuery += "&X-Amz-Signature=" + ctx.signature } else { parts := []string{ authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString, "SignedHeaders=" + ctx.signedHeaders, "Signature=" + ctx.signature, } ctx.Request.Header.Set("Authorization", strings.Join(parts, ", ")) } } func (ctx *signingCtx) buildTime() { ctx.formattedTime = ctx.Time.UTC().Format(timeFormat) ctx.formattedShortTime = ctx.Time.UTC().Format(shortTimeFormat) if ctx.isPresign { duration := int64(ctx.ExpireTime / time.Second) ctx.Query.Set("X-Amz-Date", ctx.formattedTime) ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10)) } else { ctx.Request.Header.Set("X-Amz-Date", ctx.formattedTime) } } func (ctx *signingCtx) buildCredentialString() { ctx.credentialString = strings.Join([]string{ ctx.formattedShortTime, ctx.Region, ctx.ServiceName, "aws4_request", }, "/") if ctx.isPresign { ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString) } } func buildQuery(r rule, header http.Header) (url.Values, http.Header) { query := url.Values{} unsignedHeaders := http.Header{} for k, h := range header { if r.IsValid(k) { query[k] = h } else { unsignedHeaders[k] = h } } return query, unsignedHeaders } func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) { var headers []string headers = append(headers, "host") for k, v := range header { canonicalKey := http.CanonicalHeaderKey(k) if !r.IsValid(canonicalKey) { continue // ignored header } if ctx.SignedHeaderVals == nil { ctx.SignedHeaderVals = make(http.Header) } lowerCaseKey := strings.ToLower(k) if _, ok := ctx.SignedHeaderVals[lowerCaseKey]; ok { // include additional values ctx.SignedHeaderVals[lowerCaseKey] = append(ctx.SignedHeaderVals[lowerCaseKey], v...) continue } headers = append(headers, lowerCaseKey) ctx.SignedHeaderVals[lowerCaseKey] = v } sort.Strings(headers) ctx.signedHeaders = strings.Join(headers, ";") if ctx.isPresign { ctx.Query.Set("X-Amz-SignedHeaders", ctx.signedHeaders) } headerValues := make([]string, len(headers)) for i, k := range headers { if k == "host" { headerValues[i] = "host:" + ctx.Request.URL.Host } else { headerValues[i] = k + ":" + strings.Join(ctx.SignedHeaderVals[k], ",") } } ctx.canonicalHeaders = strings.Join(stripExcessSpaces(headerValues), "\n") } func (ctx *signingCtx) buildCanonicalString() { ctx.Request.URL.RawQuery = strings.Replace(ctx.Query.Encode(), "+", "%20", -1) uri := ctx.Request.URL.Opaque if uri != "" { uri = "/" + strings.Join(strings.Split(uri, "/")[3:], "/") } else { uri = ctx.Request.URL.Path } if uri == "" { uri = "/" } if ctx.ServiceName != "s3" { uri = rest.EscapePath(uri, false) } ctx.canonicalString = strings.Join([]string{ ctx.Request.Method, uri, ctx.Request.URL.RawQuery, ctx.canonicalHeaders + "\n", ctx.signedHeaders, ctx.bodyDigest, }, "\n") } func (ctx *signingCtx) buildStringToSign() { ctx.stringToSign = strings.Join([]string{ authHeaderPrefix, ctx.formattedTime, ctx.credentialString, hex.EncodeToString(makeSha256([]byte(ctx.canonicalString))), }, "\n") } func (ctx *signingCtx) buildSignature() { secret := ctx.credValues.SecretAccessKey date := makeHmac([]byte("AWS4"+secret), []byte(ctx.formattedShortTime)) region := makeHmac(date, []byte(ctx.Region)) service := makeHmac(region, []byte(ctx.ServiceName)) credentials := makeHmac(service, []byte("aws4_request")) signature := makeHmac(credentials, []byte(ctx.stringToSign)) ctx.signature = hex.EncodeToString(signature) } func (ctx *signingCtx) buildBodyDigest() { hash := ctx.Request.Header.Get("X-Amz-Content-Sha256") if hash == "" { if ctx.isPresign && ctx.ServiceName == "s3" { hash = "UNSIGNED-PAYLOAD" } else if ctx.Body == nil { hash = emptyStringSHA256 } else { hash = hex.EncodeToString(makeSha256Reader(ctx.Body)) } if ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" { ctx.Request.Header.Set("X-Amz-Content-Sha256", hash) } } ctx.bodyDigest = hash } // isRequestSigned returns if the request is currently signed or presigned func (ctx *signingCtx) isRequestSigned() bool { if ctx.isPresign && ctx.Query.Get("X-Amz-Signature") != "" { return true } if ctx.Request.Header.Get("Authorization") != "" { return true } return false } // unsign removes signing flags for both signed and presigned requests. func (ctx *signingCtx) removePresign() { ctx.Query.Del("X-Amz-Algorithm") ctx.Query.Del("X-Amz-Signature") ctx.Query.Del("X-Amz-Security-Token") ctx.Query.Del("X-Amz-Date") ctx.Query.Del("X-Amz-Expires") ctx.Query.Del("X-Amz-Credential") ctx.Query.Del("X-Amz-SignedHeaders") } func makeHmac(key []byte, data []byte) []byte { hash := hmac.New(sha256.New, key) hash.Write(data) return hash.Sum(nil) } func makeSha256(data []byte) []byte { hash := sha256.New() hash.Write(data) return hash.Sum(nil) } func makeSha256Reader(reader io.ReadSeeker) []byte { hash := sha256.New() start, _ := reader.Seek(0, 1) defer reader.Seek(start, 0) io.Copy(hash, reader) return hash.Sum(nil) } const doubleSpaces = " " var doubleSpaceBytes = []byte(doubleSpaces) func stripExcessSpaces(headerVals []string) []string { vals := make([]string, len(headerVals)) for i, str := range headerVals { // Trim leading and trailing spaces trimmed := strings.TrimSpace(str) idx := strings.Index(trimmed, doubleSpaces) var buf []byte for idx > -1 { // Multiple adjacent spaces found if buf == nil { // first time create the buffer buf = []byte(trimmed) } stripToIdx := -1 for j := idx + 1; j < len(buf); j++ { if buf[j] != ' ' { buf = append(buf[:idx+1], buf[j:]...) stripToIdx = j break } } if stripToIdx >= 0 { idx = bytes.Index(buf[stripToIdx:], doubleSpaceBytes) if idx >= 0 { idx += stripToIdx } } else { idx = -1 } } if buf != nil { vals[i] = string(buf) } else { vals[i] = trimmed } } return vals } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/types.go ================================================ package aws import ( "io" "sync" ) // ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser func ReadSeekCloser(r io.Reader) ReaderSeekerCloser { return ReaderSeekerCloser{r} } // ReaderSeekerCloser represents a reader that can also delegate io.Seeker and // io.Closer interfaces to the underlying object if they are available. type ReaderSeekerCloser struct { r io.Reader } // Read reads from the reader up to size of p. The number of bytes read, and // error if it occurred will be returned. // // If the reader is not an io.Reader zero bytes read, and nil error will be returned. // // Performs the same functionality as io.Reader Read func (r ReaderSeekerCloser) Read(p []byte) (int, error) { switch t := r.r.(type) { case io.Reader: return t.Read(p) } return 0, nil } // Seek sets the offset for the next Read to offset, interpreted according to // whence: 0 means relative to the origin of the file, 1 means relative to the // current offset, and 2 means relative to the end. Seek returns the new offset // and an error, if any. // // If the ReaderSeekerCloser is not an io.Seeker nothing will be done. func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) { switch t := r.r.(type) { case io.Seeker: return t.Seek(offset, whence) } return int64(0), nil } // Close closes the ReaderSeekerCloser. // // If the ReaderSeekerCloser is not an io.Closer nothing will be done. func (r ReaderSeekerCloser) Close() error { switch t := r.r.(type) { case io.Closer: return t.Close() } return nil } // A WriteAtBuffer provides a in memory buffer supporting the io.WriterAt interface // Can be used with the s3manager.Downloader to download content to a buffer // in memory. Safe to use concurrently. type WriteAtBuffer struct { buf []byte m sync.Mutex // GrowthCoeff defines the growth rate of the internal buffer. By // default, the growth rate is 1, where expanding the internal // buffer will allocate only enough capacity to fit the new expected // length. GrowthCoeff float64 } // NewWriteAtBuffer creates a WriteAtBuffer with an internal buffer // provided by buf. func NewWriteAtBuffer(buf []byte) *WriteAtBuffer { return &WriteAtBuffer{buf: buf} } // WriteAt writes a slice of bytes to a buffer starting at the position provided // The number of bytes written will be returned, or error. Can overwrite previous // written slices if the write ats overlap. func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) { pLen := len(p) expLen := pos + int64(pLen) b.m.Lock() defer b.m.Unlock() if int64(len(b.buf)) < expLen { if int64(cap(b.buf)) < expLen { if b.GrowthCoeff < 1 { b.GrowthCoeff = 1 } newBuf := make([]byte, expLen, int64(b.GrowthCoeff*float64(expLen))) copy(newBuf, b.buf) b.buf = newBuf } b.buf = b.buf[:expLen] } copy(b.buf[pos:], p) return pLen, nil } // Bytes returns a slice of bytes written to the buffer. func (b *WriteAtBuffer) Bytes() []byte { b.m.Lock() defer b.m.Unlock() return b.buf[:len(b.buf):len(b.buf)] } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/aws/version.go ================================================ // Package aws provides core functionality for making requests to AWS services. package aws // SDKName is the name of this AWS SDK const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK const SDKVersion = "1.4.10" ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/endpoints/endpoints.go ================================================ // Package endpoints validates regional endpoints for services. package endpoints //go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go //go:generate gofmt -s -w endpoints_map.go import ( "fmt" "regexp" "strings" ) // NormalizeEndpoint takes and endpoint and service API information to return a // normalized endpoint and signing region. If the endpoint is not an empty string // the service name and region will be used to look up the service's API endpoint. // If the endpoint is provided the scheme will be added if it is not present. func NormalizeEndpoint(endpoint, serviceName, region string, disableSSL, useDualStack bool) (normEndpoint, signingRegion string) { if endpoint == "" { return EndpointForRegion(serviceName, region, disableSSL, useDualStack) } return AddScheme(endpoint, disableSSL), "" } // EndpointForRegion returns an endpoint and its signing region for a service and region. // if the service and region pair are not found endpoint and signingRegion will be empty. func EndpointForRegion(svcName, region string, disableSSL, useDualStack bool) (endpoint, signingRegion string) { dualStackField := "" if useDualStack { dualStackField = "/dualstack" } derivedKeys := []string{ region + "/" + svcName + dualStackField, region + "/*" + dualStackField, "*/" + svcName + dualStackField, "*/*" + dualStackField, } for _, key := range derivedKeys { if val, ok := endpointsMap.Endpoints[key]; ok { ep := val.Endpoint ep = strings.Replace(ep, "{region}", region, -1) ep = strings.Replace(ep, "{service}", svcName, -1) endpoint = ep signingRegion = val.SigningRegion break } } return AddScheme(endpoint, disableSSL), signingRegion } // Regular expression to determine if the endpoint string is prefixed with a scheme. var schemeRE = regexp.MustCompile("^([^:]+)://") // AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no // scheme. If disableSSL is true HTTP will be added instead of the default HTTPS. func AddScheme(endpoint string, disableSSL bool) string { if endpoint != "" && !schemeRE.MatchString(endpoint) { scheme := "https" if disableSSL { scheme = "http" } endpoint = fmt.Sprintf("%s://%s", scheme, endpoint) } return endpoint } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/endpoints/endpoints.json ================================================ { "version": 2, "endpoints": { "*/*": { "endpoint": "{service}.{region}.amazonaws.com" }, "cn-north-1/*": { "endpoint": "{service}.{region}.amazonaws.com.cn", "signatureVersion": "v4" }, "cn-north-1/ec2metadata": { "endpoint": "http://169.254.169.254/latest" }, "us-gov-west-1/iam": { "endpoint": "iam.us-gov.amazonaws.com" }, "us-gov-west-1/sts": { "endpoint": "sts.us-gov-west-1.amazonaws.com" }, "us-gov-west-1/s3": { "endpoint": "s3-{region}.amazonaws.com" }, "us-gov-west-1/ec2metadata": { "endpoint": "http://169.254.169.254/latest" }, "*/cloudfront": { "endpoint": "cloudfront.amazonaws.com", "signingRegion": "us-east-1" }, "*/cloudsearchdomain": { "endpoint": "", "signingRegion": "us-east-1" }, "*/data.iot": { "endpoint": "", "signingRegion": "us-east-1" }, "*/ec2metadata": { "endpoint": "http://169.254.169.254/latest" }, "*/iam": { "endpoint": "iam.amazonaws.com", "signingRegion": "us-east-1" }, "*/importexport": { "endpoint": "importexport.amazonaws.com", "signingRegion": "us-east-1" }, "*/route53": { "endpoint": "route53.amazonaws.com", "signingRegion": "us-east-1" }, "*/sts": { "endpoint": "sts.amazonaws.com", "signingRegion": "us-east-1" }, "*/waf": { "endpoint": "waf.amazonaws.com", "signingRegion": "us-east-1" }, "us-east-1/sdb": { "endpoint": "sdb.amazonaws.com", "signingRegion": "us-east-1" }, "*/s3": { "endpoint": "s3-{region}.amazonaws.com" }, "*/s3/dualstack": { "endpoint": "s3.dualstack.{region}.amazonaws.com" }, "us-east-1/s3": { "endpoint": "s3.amazonaws.com" }, "eu-central-1/s3": { "endpoint": "{service}.{region}.amazonaws.com" } } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/endpoints/endpoints_map.go ================================================ package endpoints // THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. type endpointStruct struct { Version int Endpoints map[string]endpointEntry } type endpointEntry struct { Endpoint string SigningRegion string } var endpointsMap = endpointStruct{ Version: 2, Endpoints: map[string]endpointEntry{ "*/*": { Endpoint: "{service}.{region}.amazonaws.com", }, "*/cloudfront": { Endpoint: "cloudfront.amazonaws.com", SigningRegion: "us-east-1", }, "*/cloudsearchdomain": { Endpoint: "", SigningRegion: "us-east-1", }, "*/data.iot": { Endpoint: "", SigningRegion: "us-east-1", }, "*/ec2metadata": { Endpoint: "http://169.254.169.254/latest", }, "*/iam": { Endpoint: "iam.amazonaws.com", SigningRegion: "us-east-1", }, "*/importexport": { Endpoint: "importexport.amazonaws.com", SigningRegion: "us-east-1", }, "*/route53": { Endpoint: "route53.amazonaws.com", SigningRegion: "us-east-1", }, "*/s3": { Endpoint: "s3-{region}.amazonaws.com", }, "*/s3/dualstack": { Endpoint: "s3.dualstack.{region}.amazonaws.com", }, "*/sts": { Endpoint: "sts.amazonaws.com", SigningRegion: "us-east-1", }, "*/waf": { Endpoint: "waf.amazonaws.com", SigningRegion: "us-east-1", }, "cn-north-1/*": { Endpoint: "{service}.{region}.amazonaws.com.cn", }, "cn-north-1/ec2metadata": { Endpoint: "http://169.254.169.254/latest", }, "eu-central-1/s3": { Endpoint: "{service}.{region}.amazonaws.com", }, "us-east-1/s3": { Endpoint: "s3.amazonaws.com", }, "us-east-1/sdb": { Endpoint: "sdb.amazonaws.com", SigningRegion: "us-east-1", }, "us-gov-west-1/ec2metadata": { Endpoint: "http://169.254.169.254/latest", }, "us-gov-west-1/iam": { Endpoint: "iam.us-gov.amazonaws.com", }, "us-gov-west-1/s3": { Endpoint: "s3-{region}.amazonaws.com", }, "us-gov-west-1/sts": { Endpoint: "sts.us-gov-west-1.amazonaws.com", }, }, } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency.go ================================================ package protocol import ( "crypto/rand" "fmt" "reflect" ) // RandReader is the random reader the protocol package will use to read // random bytes from. This is exported for testing, and should not be used. var RandReader = rand.Reader const idempotencyTokenFillTag = `idempotencyToken` // CanSetIdempotencyToken returns true if the struct field should be // automatically populated with a Idempotency token. // // Only *string and string type fields that are tagged with idempotencyToken // which are not already set can be auto filled. func CanSetIdempotencyToken(v reflect.Value, f reflect.StructField) bool { switch u := v.Interface().(type) { // To auto fill an Idempotency token the field must be a string, // tagged for auto fill, and have a zero value. case *string: return u == nil && len(f.Tag.Get(idempotencyTokenFillTag)) != 0 case string: return len(u) == 0 && len(f.Tag.Get(idempotencyTokenFillTag)) != 0 } return false } // GetIdempotencyToken returns a randomly generated idempotency token. func GetIdempotencyToken() string { b := make([]byte, 16) RandReader.Read(b) return UUIDVersion4(b) } // SetIdempotencyToken will set the value provided with a Idempotency Token. // Given that the value can be set. Will panic if value is not setable. func SetIdempotencyToken(v reflect.Value) { if v.Kind() == reflect.Ptr { if v.IsNil() && v.CanSet() { v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() } v = reflect.Indirect(v) if !v.CanSet() { panic(fmt.Sprintf("unable to set idempotnecy token %v", v)) } b := make([]byte, 16) _, err := rand.Read(b) if err != nil { // TODO handle error return } v.Set(reflect.ValueOf(UUIDVersion4(b))) } // UUIDVersion4 returns a Version 4 random UUID from the byte slice provided func UUIDVersion4(u []byte) string { // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29 // 13th character is "4" u[6] = (u[6] | 0x40) & 0x4F // 17th character is "8", "9", "a", or "b" u[8] = (u[8] | 0x80) & 0xBF return fmt.Sprintf(`%X-%X-%X-%X-%X`, u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/build.go ================================================ // Package jsonutil provides JSON serialization of AWS requests and responses. package jsonutil import ( "bytes" "encoding/base64" "fmt" "reflect" "sort" "strconv" "time" "github.com/aws/aws-sdk-go/private/protocol" ) var timeType = reflect.ValueOf(time.Time{}).Type() var byteSliceType = reflect.ValueOf([]byte{}).Type() // BuildJSON builds a JSON string for a given object v. func BuildJSON(v interface{}) ([]byte, error) { var buf bytes.Buffer err := buildAny(reflect.ValueOf(v), &buf, "") return buf.Bytes(), err } func buildAny(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { value = reflect.Indirect(value) if !value.IsValid() { return nil } vtype := value.Type() t := tag.Get("type") if t == "" { switch vtype.Kind() { case reflect.Struct: // also it can't be a time object if value.Type() != timeType { t = "structure" } case reflect.Slice: // also it can't be a byte slice if _, ok := value.Interface().([]byte); !ok { t = "list" } case reflect.Map: t = "map" } } switch t { case "structure": if field, ok := vtype.FieldByName("_"); ok { tag = field.Tag } return buildStruct(value, buf, tag) case "list": return buildList(value, buf, tag) case "map": return buildMap(value, buf, tag) default: return buildScalar(value, buf, tag) } } func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { if !value.IsValid() { return nil } // unwrap payloads if payload := tag.Get("payload"); payload != "" { field, _ := value.Type().FieldByName(payload) tag = field.Tag value = elemOf(value.FieldByName(payload)) if !value.IsValid() { return nil } } buf.WriteByte('{') t := value.Type() first := true for i := 0; i < t.NumField(); i++ { member := value.Field(i) field := t.Field(i) if field.PkgPath != "" { continue // ignore unexported fields } if field.Tag.Get("json") == "-" { continue } if field.Tag.Get("location") != "" { continue // ignore non-body elements } if protocol.CanSetIdempotencyToken(member, field) { token := protocol.GetIdempotencyToken() member = reflect.ValueOf(&token) } if (member.Kind() == reflect.Ptr || member.Kind() == reflect.Slice || member.Kind() == reflect.Map) && member.IsNil() { continue // ignore unset fields } if first { first = false } else { buf.WriteByte(',') } // figure out what this field is called name := field.Name if locName := field.Tag.Get("locationName"); locName != "" { name = locName } writeString(name, buf) buf.WriteString(`:`) err := buildAny(member, buf, field.Tag) if err != nil { return err } } buf.WriteString("}") return nil } func buildList(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { buf.WriteString("[") for i := 0; i < value.Len(); i++ { buildAny(value.Index(i), buf, "") if i < value.Len()-1 { buf.WriteString(",") } } buf.WriteString("]") return nil } type sortedValues []reflect.Value func (sv sortedValues) Len() int { return len(sv) } func (sv sortedValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } func (sv sortedValues) Less(i, j int) bool { return sv[i].String() < sv[j].String() } func buildMap(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { buf.WriteString("{") sv := sortedValues(value.MapKeys()) sort.Sort(sv) for i, k := range sv { if i > 0 { buf.WriteByte(',') } writeString(k.String(), buf) buf.WriteString(`:`) buildAny(value.MapIndex(k), buf, "") } buf.WriteString("}") return nil } func buildScalar(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { switch value.Kind() { case reflect.String: writeString(value.String(), buf) case reflect.Bool: buf.WriteString(strconv.FormatBool(value.Bool())) case reflect.Int64: buf.WriteString(strconv.FormatInt(value.Int(), 10)) case reflect.Float64: buf.WriteString(strconv.FormatFloat(value.Float(), 'f', -1, 64)) default: switch value.Type() { case timeType: converted := value.Interface().(time.Time) buf.WriteString(strconv.FormatInt(converted.UTC().Unix(), 10)) case byteSliceType: if !value.IsNil() { converted := value.Interface().([]byte) buf.WriteByte('"') if len(converted) < 1024 { // for small buffers, using Encode directly is much faster. dst := make([]byte, base64.StdEncoding.EncodedLen(len(converted))) base64.StdEncoding.Encode(dst, converted) buf.Write(dst) } else { // for large buffers, avoid unnecessary extra temporary // buffer space. enc := base64.NewEncoder(base64.StdEncoding, buf) enc.Write(converted) enc.Close() } buf.WriteByte('"') } default: return fmt.Errorf("unsupported JSON value %v (%s)", value.Interface(), value.Type()) } } return nil } func writeString(s string, buf *bytes.Buffer) { buf.WriteByte('"') for _, r := range s { if r == '"' { buf.WriteString(`\"`) } else if r == '\\' { buf.WriteString(`\\`) } else if r == '\b' { buf.WriteString(`\b`) } else if r == '\f' { buf.WriteString(`\f`) } else if r == '\r' { buf.WriteString(`\r`) } else if r == '\t' { buf.WriteString(`\t`) } else if r == '\n' { buf.WriteString(`\n`) } else if r < 32 { fmt.Fprintf(buf, "\\u%0.4x", r) } else { buf.WriteRune(r) } } buf.WriteByte('"') } // Returns the reflection element of a value, if it is a pointer. func elemOf(value reflect.Value) reflect.Value { for value.Kind() == reflect.Ptr { value = value.Elem() } return value } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/json/jsonutil/unmarshal.go ================================================ package jsonutil import ( "encoding/base64" "encoding/json" "fmt" "io" "io/ioutil" "reflect" "time" ) // UnmarshalJSON reads a stream and unmarshals the results in object v. func UnmarshalJSON(v interface{}, stream io.Reader) error { var out interface{} b, err := ioutil.ReadAll(stream) if err != nil { return err } if len(b) == 0 { return nil } if err := json.Unmarshal(b, &out); err != nil { return err } return unmarshalAny(reflect.ValueOf(v), out, "") } func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error { vtype := value.Type() if vtype.Kind() == reflect.Ptr { vtype = vtype.Elem() // check kind of actual element type } t := tag.Get("type") if t == "" { switch vtype.Kind() { case reflect.Struct: // also it can't be a time object if _, ok := value.Interface().(*time.Time); !ok { t = "structure" } case reflect.Slice: // also it can't be a byte slice if _, ok := value.Interface().([]byte); !ok { t = "list" } case reflect.Map: t = "map" } } switch t { case "structure": if field, ok := vtype.FieldByName("_"); ok { tag = field.Tag } return unmarshalStruct(value, data, tag) case "list": return unmarshalList(value, data, tag) case "map": return unmarshalMap(value, data, tag) default: return unmarshalScalar(value, data, tag) } } func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error { if data == nil { return nil } mapData, ok := data.(map[string]interface{}) if !ok { return fmt.Errorf("JSON value is not a structure (%#v)", data) } t := value.Type() if value.Kind() == reflect.Ptr { if value.IsNil() { // create the structure if it's nil s := reflect.New(value.Type().Elem()) value.Set(s) value = s } value = value.Elem() t = t.Elem() } // unwrap any payloads if payload := tag.Get("payload"); payload != "" { field, _ := t.FieldByName(payload) return unmarshalAny(value.FieldByName(payload), data, field.Tag) } for i := 0; i < t.NumField(); i++ { field := t.Field(i) if field.PkgPath != "" { continue // ignore unexported fields } // figure out what this field is called name := field.Name if locName := field.Tag.Get("locationName"); locName != "" { name = locName } member := value.FieldByIndex(field.Index) err := unmarshalAny(member, mapData[name], field.Tag) if err != nil { return err } } return nil } func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error { if data == nil { return nil } listData, ok := data.([]interface{}) if !ok { return fmt.Errorf("JSON value is not a list (%#v)", data) } if value.IsNil() { l := len(listData) value.Set(reflect.MakeSlice(value.Type(), l, l)) } for i, c := range listData { err := unmarshalAny(value.Index(i), c, "") if err != nil { return err } } return nil } func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error { if data == nil { return nil } mapData, ok := data.(map[string]interface{}) if !ok { return fmt.Errorf("JSON value is not a map (%#v)", data) } if value.IsNil() { value.Set(reflect.MakeMap(value.Type())) } for k, v := range mapData { kvalue := reflect.ValueOf(k) vvalue := reflect.New(value.Type().Elem()).Elem() unmarshalAny(vvalue, v, "") value.SetMapIndex(kvalue, vvalue) } return nil } func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error { errf := func() error { return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type()) } switch d := data.(type) { case nil: return nil // nothing to do here case string: switch value.Interface().(type) { case *string: value.Set(reflect.ValueOf(&d)) case []byte: b, err := base64.StdEncoding.DecodeString(d) if err != nil { return err } value.Set(reflect.ValueOf(b)) default: return errf() } case float64: switch value.Interface().(type) { case *int64: di := int64(d) value.Set(reflect.ValueOf(&di)) case *float64: value.Set(reflect.ValueOf(&d)) case *time.Time: t := time.Unix(int64(d), 0).UTC() value.Set(reflect.ValueOf(&t)) default: return errf() } case bool: switch value.Interface().(type) { case *bool: value.Set(reflect.ValueOf(&d)) default: return errf() } default: return fmt.Errorf("unsupported JSON value (%v)", data) } return nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/jsonrpc/jsonrpc.go ================================================ // Package jsonrpc provides JSON RPC utilities for serialization of AWS // requests and responses. package jsonrpc //go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go //go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go import ( "encoding/json" "io/ioutil" "strings" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" "github.com/aws/aws-sdk-go/private/protocol/rest" ) var emptyJSON = []byte("{}") // BuildHandler is a named request handler for building jsonrpc protocol requests var BuildHandler = request.NamedHandler{Name: "awssdk.jsonrpc.Build", Fn: Build} // UnmarshalHandler is a named request handler for unmarshaling jsonrpc protocol requests var UnmarshalHandler = request.NamedHandler{Name: "awssdk.jsonrpc.Unmarshal", Fn: Unmarshal} // UnmarshalMetaHandler is a named request handler for unmarshaling jsonrpc protocol request metadata var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.jsonrpc.UnmarshalMeta", Fn: UnmarshalMeta} // UnmarshalErrorHandler is a named request handler for unmarshaling jsonrpc protocol request errors var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.jsonrpc.UnmarshalError", Fn: UnmarshalError} // Build builds a JSON payload for a JSON RPC request. func Build(req *request.Request) { var buf []byte var err error if req.ParamsFilled() { buf, err = jsonutil.BuildJSON(req.Params) if err != nil { req.Error = awserr.New("SerializationError", "failed encoding JSON RPC request", err) return } } else { buf = emptyJSON } if req.ClientInfo.TargetPrefix != "" || string(buf) != "{}" { req.SetBufferBody(buf) } if req.ClientInfo.TargetPrefix != "" { target := req.ClientInfo.TargetPrefix + "." + req.Operation.Name req.HTTPRequest.Header.Add("X-Amz-Target", target) } if req.ClientInfo.JSONVersion != "" { jsonVersion := req.ClientInfo.JSONVersion req.HTTPRequest.Header.Add("Content-Type", "application/x-amz-json-"+jsonVersion) } } // Unmarshal unmarshals a response for a JSON RPC service. func Unmarshal(req *request.Request) { defer req.HTTPResponse.Body.Close() if req.DataFilled() { err := jsonutil.UnmarshalJSON(req.Data, req.HTTPResponse.Body) if err != nil { req.Error = awserr.New("SerializationError", "failed decoding JSON RPC response", err) } } return } // UnmarshalMeta unmarshals headers from a response for a JSON RPC service. func UnmarshalMeta(req *request.Request) { rest.UnmarshalMeta(req) } // UnmarshalError unmarshals an error response for a JSON RPC service. func UnmarshalError(req *request.Request) { defer req.HTTPResponse.Body.Close() bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body) if err != nil { req.Error = awserr.New("SerializationError", "failed reading JSON RPC error response", err) return } if len(bodyBytes) == 0 { req.Error = awserr.NewRequestFailure( awserr.New("SerializationError", req.HTTPResponse.Status, nil), req.HTTPResponse.StatusCode, "", ) return } var jsonErr jsonErrorResponse if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { req.Error = awserr.New("SerializationError", "failed decoding JSON RPC error response", err) return } codes := strings.SplitN(jsonErr.Code, "#", 2) req.Error = awserr.NewRequestFailure( awserr.New(codes[len(codes)-1], jsonErr.Message, nil), req.HTTPResponse.StatusCode, req.RequestID, ) } type jsonErrorResponse struct { Code string `json:"__type"` Message string `json:"message"` } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/query/build.go ================================================ // Package query provides serialization of AWS query requests, and responses. package query //go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go import ( "net/url" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/private/protocol/query/queryutil" ) // BuildHandler is a named request handler for building query protocol requests var BuildHandler = request.NamedHandler{Name: "awssdk.query.Build", Fn: Build} // Build builds a request for an AWS Query service. func Build(r *request.Request) { body := url.Values{ "Action": {r.Operation.Name}, "Version": {r.ClientInfo.APIVersion}, } if err := queryutil.Parse(body, r.Params, false); err != nil { r.Error = awserr.New("SerializationError", "failed encoding Query request", err) return } if r.ExpireTime == 0 { r.HTTPRequest.Method = "POST" r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") r.SetBufferBody([]byte(body.Encode())) } else { // This is a pre-signed request r.HTTPRequest.Method = "GET" r.HTTPRequest.URL.RawQuery = body.Encode() } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/query/queryutil/queryutil.go ================================================ package queryutil import ( "encoding/base64" "fmt" "net/url" "reflect" "sort" "strconv" "strings" "time" "github.com/aws/aws-sdk-go/private/protocol" ) // Parse parses an object i and fills a url.Values object. The isEC2 flag // indicates if this is the EC2 Query sub-protocol. func Parse(body url.Values, i interface{}, isEC2 bool) error { q := queryParser{isEC2: isEC2} return q.parseValue(body, reflect.ValueOf(i), "", "") } func elemOf(value reflect.Value) reflect.Value { for value.Kind() == reflect.Ptr { value = value.Elem() } return value } type queryParser struct { isEC2 bool } func (q *queryParser) parseValue(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error { value = elemOf(value) // no need to handle zero values if !value.IsValid() { return nil } t := tag.Get("type") if t == "" { switch value.Kind() { case reflect.Struct: t = "structure" case reflect.Slice: t = "list" case reflect.Map: t = "map" } } switch t { case "structure": return q.parseStruct(v, value, prefix) case "list": return q.parseList(v, value, prefix, tag) case "map": return q.parseMap(v, value, prefix, tag) default: return q.parseScalar(v, value, prefix, tag) } } func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix string) error { if !value.IsValid() { return nil } t := value.Type() for i := 0; i < value.NumField(); i++ { elemValue := elemOf(value.Field(i)) field := t.Field(i) if field.PkgPath != "" { continue // ignore unexported fields } if protocol.CanSetIdempotencyToken(value.Field(i), field) { token := protocol.GetIdempotencyToken() elemValue = reflect.ValueOf(token) } var name string if q.isEC2 { name = field.Tag.Get("queryName") } if name == "" { if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" { name = field.Tag.Get("locationNameList") } else if locName := field.Tag.Get("locationName"); locName != "" { name = locName } if name != "" && q.isEC2 { name = strings.ToUpper(name[0:1]) + name[1:] } } if name == "" { name = field.Name } if prefix != "" { name = prefix + "." + name } if err := q.parseValue(v, elemValue, name, field.Tag); err != nil { return err } } return nil } func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error { // If it's empty, generate an empty value if !value.IsNil() && value.Len() == 0 { v.Set(prefix, "") return nil } // check for unflattened list member if !q.isEC2 && tag.Get("flattened") == "" { prefix += ".member" } for i := 0; i < value.Len(); i++ { slicePrefix := prefix if slicePrefix == "" { slicePrefix = strconv.Itoa(i + 1) } else { slicePrefix = slicePrefix + "." + strconv.Itoa(i+1) } if err := q.parseValue(v, value.Index(i), slicePrefix, ""); err != nil { return err } } return nil } func (q *queryParser) parseMap(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error { // If it's empty, generate an empty value if !value.IsNil() && value.Len() == 0 { v.Set(prefix, "") return nil } // check for unflattened list member if !q.isEC2 && tag.Get("flattened") == "" { prefix += ".entry" } // sort keys for improved serialization consistency. // this is not strictly necessary for protocol support. mapKeyValues := value.MapKeys() mapKeys := map[string]reflect.Value{} mapKeyNames := make([]string, len(mapKeyValues)) for i, mapKey := range mapKeyValues { name := mapKey.String() mapKeys[name] = mapKey mapKeyNames[i] = name } sort.Strings(mapKeyNames) for i, mapKeyName := range mapKeyNames { mapKey := mapKeys[mapKeyName] mapValue := value.MapIndex(mapKey) kname := tag.Get("locationNameKey") if kname == "" { kname = "key" } vname := tag.Get("locationNameValue") if vname == "" { vname = "value" } // serialize key var keyName string if prefix == "" { keyName = strconv.Itoa(i+1) + "." + kname } else { keyName = prefix + "." + strconv.Itoa(i+1) + "." + kname } if err := q.parseValue(v, mapKey, keyName, ""); err != nil { return err } // serialize value var valueName string if prefix == "" { valueName = strconv.Itoa(i+1) + "." + vname } else { valueName = prefix + "." + strconv.Itoa(i+1) + "." + vname } if err := q.parseValue(v, mapValue, valueName, ""); err != nil { return err } } return nil } func (q *queryParser) parseScalar(v url.Values, r reflect.Value, name string, tag reflect.StructTag) error { switch value := r.Interface().(type) { case string: v.Set(name, value) case []byte: if !r.IsNil() { v.Set(name, base64.StdEncoding.EncodeToString(value)) } case bool: v.Set(name, strconv.FormatBool(value)) case int64: v.Set(name, strconv.FormatInt(value, 10)) case int: v.Set(name, strconv.Itoa(value)) case float64: v.Set(name, strconv.FormatFloat(value, 'f', -1, 64)) case float32: v.Set(name, strconv.FormatFloat(float64(value), 'f', -1, 32)) case time.Time: const ISO8601UTC = "2006-01-02T15:04:05Z" v.Set(name, value.UTC().Format(ISO8601UTC)) default: return fmt.Errorf("unsupported value for param %s: %v (%s)", name, r.Interface(), r.Type().Name()) } return nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal.go ================================================ package query //go:generate go run ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go import ( "encoding/xml" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" ) // UnmarshalHandler is a named request handler for unmarshaling query protocol requests var UnmarshalHandler = request.NamedHandler{Name: "awssdk.query.Unmarshal", Fn: Unmarshal} // UnmarshalMetaHandler is a named request handler for unmarshaling query protocol request metadata var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalMeta", Fn: UnmarshalMeta} // Unmarshal unmarshals a response for an AWS Query service. func Unmarshal(r *request.Request) { defer r.HTTPResponse.Body.Close() if r.DataFilled() { decoder := xml.NewDecoder(r.HTTPResponse.Body) err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result") if err != nil { r.Error = awserr.New("SerializationError", "failed decoding Query response", err) return } } } // UnmarshalMeta unmarshals header response values for an AWS Query service. func UnmarshalMeta(r *request.Request) { r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid") } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_error.go ================================================ package query import ( "encoding/xml" "io/ioutil" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" ) type xmlErrorResponse struct { XMLName xml.Name `xml:"ErrorResponse"` Code string `xml:"Error>Code"` Message string `xml:"Error>Message"` RequestID string `xml:"RequestId"` } type xmlServiceUnavailableResponse struct { XMLName xml.Name `xml:"ServiceUnavailableException"` } // UnmarshalErrorHandler is a name request handler to unmarshal request errors var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalError", Fn: UnmarshalError} // UnmarshalError unmarshals an error response for an AWS Query service. func UnmarshalError(r *request.Request) { defer r.HTTPResponse.Body.Close() bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body) if err != nil { r.Error = awserr.New("SerializationError", "failed to read from query HTTP response body", err) return } // First check for specific error resp := xmlErrorResponse{} decodeErr := xml.Unmarshal(bodyBytes, &resp) if decodeErr == nil { reqID := resp.RequestID if reqID == "" { reqID = r.RequestID } r.Error = awserr.NewRequestFailure( awserr.New(resp.Code, resp.Message, nil), r.HTTPResponse.StatusCode, reqID, ) return } // Check for unhandled error servUnavailResp := xmlServiceUnavailableResponse{} unavailErr := xml.Unmarshal(bodyBytes, &servUnavailResp) if unavailErr == nil { r.Error = awserr.NewRequestFailure( awserr.New("ServiceUnavailableException", "service is unavailable", nil), r.HTTPResponse.StatusCode, r.RequestID, ) return } // Failed to retrieve any error message from the response body r.Error = awserr.New("SerializationError", "failed to decode query XML error response", decodeErr) } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go ================================================ // Package rest provides RESTful serialization of AWS requests and responses. package rest import ( "bytes" "encoding/base64" "fmt" "io" "net/http" "net/url" "path" "reflect" "strconv" "strings" "time" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" ) // RFC822 returns an RFC822 formatted timestamp for AWS protocols const RFC822 = "Mon, 2 Jan 2006 15:04:05 GMT" // Whether the byte value can be sent without escaping in AWS URLs var noEscape [256]bool var errValueNotSet = fmt.Errorf("value not set") func init() { for i := 0; i < len(noEscape); i++ { // AWS expects every character except these to be escaped noEscape[i] = (i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || (i >= '0' && i <= '9') || i == '-' || i == '.' || i == '_' || i == '~' } } // BuildHandler is a named request handler for building rest protocol requests var BuildHandler = request.NamedHandler{Name: "awssdk.rest.Build", Fn: Build} // Build builds the REST component of a service request. func Build(r *request.Request) { if r.ParamsFilled() { v := reflect.ValueOf(r.Params).Elem() buildLocationElements(r, v) buildBody(r, v) } } func buildLocationElements(r *request.Request, v reflect.Value) { query := r.HTTPRequest.URL.Query() for i := 0; i < v.NumField(); i++ { m := v.Field(i) if n := v.Type().Field(i).Name; n[0:1] == strings.ToLower(n[0:1]) { continue } if m.IsValid() { field := v.Type().Field(i) name := field.Tag.Get("locationName") if name == "" { name = field.Name } if m.Kind() == reflect.Ptr { m = m.Elem() } if !m.IsValid() { continue } var err error switch field.Tag.Get("location") { case "headers": // header maps err = buildHeaderMap(&r.HTTPRequest.Header, m, field.Tag.Get("locationName")) case "header": err = buildHeader(&r.HTTPRequest.Header, m, name) case "uri": err = buildURI(r.HTTPRequest.URL, m, name) case "querystring": err = buildQueryString(query, m, name) } r.Error = err } if r.Error != nil { return } } r.HTTPRequest.URL.RawQuery = query.Encode() updatePath(r.HTTPRequest.URL, r.HTTPRequest.URL.Path) } func buildBody(r *request.Request, v reflect.Value) { if field, ok := v.Type().FieldByName("_"); ok { if payloadName := field.Tag.Get("payload"); payloadName != "" { pfield, _ := v.Type().FieldByName(payloadName) if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" { payload := reflect.Indirect(v.FieldByName(payloadName)) if payload.IsValid() && payload.Interface() != nil { switch reader := payload.Interface().(type) { case io.ReadSeeker: r.SetReaderBody(reader) case []byte: r.SetBufferBody(reader) case string: r.SetStringBody(reader) default: r.Error = awserr.New("SerializationError", "failed to encode REST request", fmt.Errorf("unknown payload type %s", payload.Type())) } } } } } } func buildHeader(header *http.Header, v reflect.Value, name string) error { str, err := convertType(v) if err == errValueNotSet { return nil } else if err != nil { return awserr.New("SerializationError", "failed to encode REST request", err) } header.Add(name, str) return nil } func buildHeaderMap(header *http.Header, v reflect.Value, prefix string) error { for _, key := range v.MapKeys() { str, err := convertType(v.MapIndex(key)) if err == errValueNotSet { continue } else if err != nil { return awserr.New("SerializationError", "failed to encode REST request", err) } header.Add(prefix+key.String(), str) } return nil } func buildURI(u *url.URL, v reflect.Value, name string) error { value, err := convertType(v) if err == errValueNotSet { return nil } else if err != nil { return awserr.New("SerializationError", "failed to encode REST request", err) } uri := u.Path uri = strings.Replace(uri, "{"+name+"}", EscapePath(value, true), -1) uri = strings.Replace(uri, "{"+name+"+}", EscapePath(value, false), -1) u.Path = uri return nil } func buildQueryString(query url.Values, v reflect.Value, name string) error { switch value := v.Interface().(type) { case []*string: for _, item := range value { query.Add(name, *item) } case map[string]*string: for key, item := range value { query.Add(key, *item) } case map[string][]*string: for key, items := range value { for _, item := range items { query.Add(key, *item) } } default: str, err := convertType(v) if err == errValueNotSet { return nil } else if err != nil { return awserr.New("SerializationError", "failed to encode REST request", err) } query.Set(name, str) } return nil } func updatePath(url *url.URL, urlPath string) { scheme, query := url.Scheme, url.RawQuery hasSlash := strings.HasSuffix(urlPath, "/") // clean up path urlPath = path.Clean(urlPath) if hasSlash && !strings.HasSuffix(urlPath, "/") { urlPath += "/" } // get formatted URL minus scheme so we can build this into Opaque url.Scheme, url.Path, url.RawQuery = "", "", "" s := url.String() url.Scheme = scheme url.RawQuery = query // build opaque URI url.Opaque = s + urlPath } // EscapePath escapes part of a URL path in Amazon style func EscapePath(path string, encodeSep bool) string { var buf bytes.Buffer for i := 0; i < len(path); i++ { c := path[i] if noEscape[c] || (c == '/' && !encodeSep) { buf.WriteByte(c) } else { fmt.Fprintf(&buf, "%%%02X", c) } } return buf.String() } func convertType(v reflect.Value) (string, error) { v = reflect.Indirect(v) if !v.IsValid() { return "", errValueNotSet } var str string switch value := v.Interface().(type) { case string: str = value case []byte: str = base64.StdEncoding.EncodeToString(value) case bool: str = strconv.FormatBool(value) case int64: str = strconv.FormatInt(value, 10) case float64: str = strconv.FormatFloat(value, 'f', -1, 64) case time.Time: str = value.UTC().Format(RFC822) default: err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type()) return "", err } return str, nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/rest/payload.go ================================================ package rest import "reflect" // PayloadMember returns the payload field member of i if there is one, or nil. func PayloadMember(i interface{}) interface{} { if i == nil { return nil } v := reflect.ValueOf(i).Elem() if !v.IsValid() { return nil } if field, ok := v.Type().FieldByName("_"); ok { if payloadName := field.Tag.Get("payload"); payloadName != "" { field, _ := v.Type().FieldByName(payloadName) if field.Tag.Get("type") != "structure" { return nil } payload := v.FieldByName(payloadName) if payload.IsValid() || (payload.Kind() == reflect.Ptr && !payload.IsNil()) { return payload.Interface() } } } return nil } // PayloadType returns the type of a payload field member of i if there is one, or "". func PayloadType(i interface{}) string { v := reflect.Indirect(reflect.ValueOf(i)) if !v.IsValid() { return "" } if field, ok := v.Type().FieldByName("_"); ok { if payloadName := field.Tag.Get("payload"); payloadName != "" { if member, ok := v.Type().FieldByName(payloadName); ok { return member.Tag.Get("type") } } } return "" } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/rest/unmarshal.go ================================================ package rest import ( "encoding/base64" "fmt" "io" "io/ioutil" "net/http" "reflect" "strconv" "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" ) // UnmarshalHandler is a named request handler for unmarshaling rest protocol requests var UnmarshalHandler = request.NamedHandler{Name: "awssdk.rest.Unmarshal", Fn: Unmarshal} // UnmarshalMetaHandler is a named request handler for unmarshaling rest protocol request metadata var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.rest.UnmarshalMeta", Fn: UnmarshalMeta} // Unmarshal unmarshals the REST component of a response in a REST service. func Unmarshal(r *request.Request) { if r.DataFilled() { v := reflect.Indirect(reflect.ValueOf(r.Data)) unmarshalBody(r, v) } } // UnmarshalMeta unmarshals the REST metadata of a response in a REST service func UnmarshalMeta(r *request.Request) { r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid") if r.RequestID == "" { // Alternative version of request id in the header r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id") } if r.DataFilled() { v := reflect.Indirect(reflect.ValueOf(r.Data)) unmarshalLocationElements(r, v) } } func unmarshalBody(r *request.Request, v reflect.Value) { if field, ok := v.Type().FieldByName("_"); ok { if payloadName := field.Tag.Get("payload"); payloadName != "" { pfield, _ := v.Type().FieldByName(payloadName) if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" { payload := v.FieldByName(payloadName) if payload.IsValid() { switch payload.Interface().(type) { case []byte: defer r.HTTPResponse.Body.Close() b, err := ioutil.ReadAll(r.HTTPResponse.Body) if err != nil { r.Error = awserr.New("SerializationError", "failed to decode REST response", err) } else { payload.Set(reflect.ValueOf(b)) } case *string: defer r.HTTPResponse.Body.Close() b, err := ioutil.ReadAll(r.HTTPResponse.Body) if err != nil { r.Error = awserr.New("SerializationError", "failed to decode REST response", err) } else { str := string(b) payload.Set(reflect.ValueOf(&str)) } default: switch payload.Type().String() { case "io.ReadSeeker": payload.Set(reflect.ValueOf(aws.ReadSeekCloser(r.HTTPResponse.Body))) case "aws.ReadSeekCloser", "io.ReadCloser": payload.Set(reflect.ValueOf(r.HTTPResponse.Body)) default: io.Copy(ioutil.Discard, r.HTTPResponse.Body) defer r.HTTPResponse.Body.Close() r.Error = awserr.New("SerializationError", "failed to decode REST response", fmt.Errorf("unknown payload type %s", payload.Type())) } } } } } } } func unmarshalLocationElements(r *request.Request, v reflect.Value) { for i := 0; i < v.NumField(); i++ { m, field := v.Field(i), v.Type().Field(i) if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) { continue } if m.IsValid() { name := field.Tag.Get("locationName") if name == "" { name = field.Name } switch field.Tag.Get("location") { case "statusCode": unmarshalStatusCode(m, r.HTTPResponse.StatusCode) case "header": err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name)) if err != nil { r.Error = awserr.New("SerializationError", "failed to decode REST response", err) break } case "headers": prefix := field.Tag.Get("locationName") err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix) if err != nil { r.Error = awserr.New("SerializationError", "failed to decode REST response", err) break } } } if r.Error != nil { return } } } func unmarshalStatusCode(v reflect.Value, statusCode int) { if !v.IsValid() { return } switch v.Interface().(type) { case *int64: s := int64(statusCode) v.Set(reflect.ValueOf(&s)) } } func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error { switch r.Interface().(type) { case map[string]*string: // we only support string map value types out := map[string]*string{} for k, v := range headers { k = http.CanonicalHeaderKey(k) if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) { out[k[len(prefix):]] = &v[0] } } r.Set(reflect.ValueOf(out)) } return nil } func unmarshalHeader(v reflect.Value, header string) error { if !v.IsValid() || (header == "" && v.Elem().Kind() != reflect.String) { return nil } switch v.Interface().(type) { case *string: v.Set(reflect.ValueOf(&header)) case []byte: b, err := base64.StdEncoding.DecodeString(header) if err != nil { return err } v.Set(reflect.ValueOf(&b)) case *bool: b, err := strconv.ParseBool(header) if err != nil { return err } v.Set(reflect.ValueOf(&b)) case *int64: i, err := strconv.ParseInt(header, 10, 64) if err != nil { return err } v.Set(reflect.ValueOf(&i)) case *float64: f, err := strconv.ParseFloat(header, 64) if err != nil { return err } v.Set(reflect.ValueOf(&f)) case *time.Time: t, err := time.Parse(RFC822, header) if err != nil { return err } v.Set(reflect.ValueOf(&t)) default: err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type()) return err } return nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal.go ================================================ package protocol import ( "io" "io/ioutil" "github.com/aws/aws-sdk-go/aws/request" ) // UnmarshalDiscardBodyHandler is a named request handler to empty and close a response's body var UnmarshalDiscardBodyHandler = request.NamedHandler{Name: "awssdk.shared.UnmarshalDiscardBody", Fn: UnmarshalDiscardBody} // UnmarshalDiscardBody is a request handler to empty a response's body and closing it. func UnmarshalDiscardBody(r *request.Request) { if r.HTTPResponse == nil || r.HTTPResponse.Body == nil { return } io.Copy(ioutil.Discard, r.HTTPResponse.Body) r.HTTPResponse.Body.Close() } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/build.go ================================================ // Package xmlutil provides XML serialization of AWS requests and responses. package xmlutil import ( "encoding/base64" "encoding/xml" "fmt" "reflect" "sort" "strconv" "time" "github.com/aws/aws-sdk-go/private/protocol" ) // BuildXML will serialize params into an xml.Encoder. // Error will be returned if the serialization of any of the params or nested values fails. func BuildXML(params interface{}, e *xml.Encoder) error { b := xmlBuilder{encoder: e, namespaces: map[string]string{}} root := NewXMLElement(xml.Name{}) if err := b.buildValue(reflect.ValueOf(params), root, ""); err != nil { return err } for _, c := range root.Children { for _, v := range c { return StructToXML(e, v, false) } } return nil } // Returns the reflection element of a value, if it is a pointer. func elemOf(value reflect.Value) reflect.Value { for value.Kind() == reflect.Ptr { value = value.Elem() } return value } // A xmlBuilder serializes values from Go code to XML type xmlBuilder struct { encoder *xml.Encoder namespaces map[string]string } // buildValue generic XMLNode builder for any type. Will build value for their specific type // struct, list, map, scalar. // // Also takes a "type" tag value to set what type a value should be converted to XMLNode as. If // type is not provided reflect will be used to determine the value's type. func (b *xmlBuilder) buildValue(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { value = elemOf(value) if !value.IsValid() { // no need to handle zero values return nil } else if tag.Get("location") != "" { // don't handle non-body location values return nil } t := tag.Get("type") if t == "" { switch value.Kind() { case reflect.Struct: t = "structure" case reflect.Slice: t = "list" case reflect.Map: t = "map" } } switch t { case "structure": if field, ok := value.Type().FieldByName("_"); ok { tag = tag + reflect.StructTag(" ") + field.Tag } return b.buildStruct(value, current, tag) case "list": return b.buildList(value, current, tag) case "map": return b.buildMap(value, current, tag) default: return b.buildScalar(value, current, tag) } } // buildStruct adds a struct and its fields to the current XMLNode. All fields any any nested // types are converted to XMLNodes also. func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { if !value.IsValid() { return nil } fieldAdded := false // unwrap payloads if payload := tag.Get("payload"); payload != "" { field, _ := value.Type().FieldByName(payload) tag = field.Tag value = elemOf(value.FieldByName(payload)) if !value.IsValid() { return nil } } child := NewXMLElement(xml.Name{Local: tag.Get("locationName")}) // there is an xmlNamespace associated with this struct if prefix, uri := tag.Get("xmlPrefix"), tag.Get("xmlURI"); uri != "" { ns := xml.Attr{ Name: xml.Name{Local: "xmlns"}, Value: uri, } if prefix != "" { b.namespaces[prefix] = uri // register the namespace ns.Name.Local = "xmlns:" + prefix } child.Attr = append(child.Attr, ns) } t := value.Type() for i := 0; i < value.NumField(); i++ { member := elemOf(value.Field(i)) field := t.Field(i) if field.PkgPath != "" { continue // ignore unexported fields } mTag := field.Tag if mTag.Get("location") != "" { // skip non-body members continue } if protocol.CanSetIdempotencyToken(value.Field(i), field) { token := protocol.GetIdempotencyToken() member = reflect.ValueOf(token) } memberName := mTag.Get("locationName") if memberName == "" { memberName = field.Name mTag = reflect.StructTag(string(mTag) + ` locationName:"` + memberName + `"`) } if err := b.buildValue(member, child, mTag); err != nil { return err } fieldAdded = true } if fieldAdded { // only append this child if we have one ore more valid members current.AddChild(child) } return nil } // buildList adds the value's list items to the current XMLNode as children nodes. All // nested values in the list are converted to XMLNodes also. func (b *xmlBuilder) buildList(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { if value.IsNil() { // don't build omitted lists return nil } // check for unflattened list member flattened := tag.Get("flattened") != "" xname := xml.Name{Local: tag.Get("locationName")} if flattened { for i := 0; i < value.Len(); i++ { child := NewXMLElement(xname) current.AddChild(child) if err := b.buildValue(value.Index(i), child, ""); err != nil { return err } } } else { list := NewXMLElement(xname) current.AddChild(list) for i := 0; i < value.Len(); i++ { iname := tag.Get("locationNameList") if iname == "" { iname = "member" } child := NewXMLElement(xml.Name{Local: iname}) list.AddChild(child) if err := b.buildValue(value.Index(i), child, ""); err != nil { return err } } } return nil } // buildMap adds the value's key/value pairs to the current XMLNode as children nodes. All // nested values in the map are converted to XMLNodes also. // // Error will be returned if it is unable to build the map's values into XMLNodes func (b *xmlBuilder) buildMap(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { if value.IsNil() { // don't build omitted maps return nil } maproot := NewXMLElement(xml.Name{Local: tag.Get("locationName")}) current.AddChild(maproot) current = maproot kname, vname := "key", "value" if n := tag.Get("locationNameKey"); n != "" { kname = n } if n := tag.Get("locationNameValue"); n != "" { vname = n } // sorting is not required for compliance, but it makes testing easier keys := make([]string, value.Len()) for i, k := range value.MapKeys() { keys[i] = k.String() } sort.Strings(keys) for _, k := range keys { v := value.MapIndex(reflect.ValueOf(k)) mapcur := current if tag.Get("flattened") == "" { // add "entry" tag to non-flat maps child := NewXMLElement(xml.Name{Local: "entry"}) mapcur.AddChild(child) mapcur = child } kchild := NewXMLElement(xml.Name{Local: kname}) kchild.Text = k vchild := NewXMLElement(xml.Name{Local: vname}) mapcur.AddChild(kchild) mapcur.AddChild(vchild) if err := b.buildValue(v, vchild, ""); err != nil { return err } } return nil } // buildScalar will convert the value into a string and append it as a attribute or child // of the current XMLNode. // // The value will be added as an attribute if tag contains a "xmlAttribute" attribute value. // // Error will be returned if the value type is unsupported. func (b *xmlBuilder) buildScalar(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { var str string switch converted := value.Interface().(type) { case string: str = converted case []byte: if !value.IsNil() { str = base64.StdEncoding.EncodeToString(converted) } case bool: str = strconv.FormatBool(converted) case int64: str = strconv.FormatInt(converted, 10) case int: str = strconv.Itoa(converted) case float64: str = strconv.FormatFloat(converted, 'f', -1, 64) case float32: str = strconv.FormatFloat(float64(converted), 'f', -1, 32) case time.Time: const ISO8601UTC = "2006-01-02T15:04:05Z" str = converted.UTC().Format(ISO8601UTC) default: return fmt.Errorf("unsupported value for param %s: %v (%s)", tag.Get("locationName"), value.Interface(), value.Type().Name()) } xname := xml.Name{Local: tag.Get("locationName")} if tag.Get("xmlAttribute") != "" { // put into current node's attribute list attr := xml.Attr{Name: xname, Value: str} current.Attr = append(current.Attr, attr) } else { // regular text node current.AddChild(&XMLNode{Name: xname, Text: str}) } return nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go ================================================ package xmlutil import ( "encoding/base64" "encoding/xml" "fmt" "io" "reflect" "strconv" "strings" "time" ) // UnmarshalXML deserializes an xml.Decoder into the container v. V // needs to match the shape of the XML expected to be decoded. // If the shape doesn't match unmarshaling will fail. func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error { n, _ := XMLToStruct(d, nil) if n.Children != nil { for _, root := range n.Children { for _, c := range root { if wrappedChild, ok := c.Children[wrapper]; ok { c = wrappedChild[0] // pull out wrapped element } err := parse(reflect.ValueOf(v), c, "") if err != nil { if err == io.EOF { return nil } return err } } } return nil } return nil } // parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect // will be used to determine the type from r. func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { rtype := r.Type() if rtype.Kind() == reflect.Ptr { rtype = rtype.Elem() // check kind of actual element type } t := tag.Get("type") if t == "" { switch rtype.Kind() { case reflect.Struct: t = "structure" case reflect.Slice: t = "list" case reflect.Map: t = "map" } } switch t { case "structure": if field, ok := rtype.FieldByName("_"); ok { tag = field.Tag } return parseStruct(r, node, tag) case "list": return parseList(r, node, tag) case "map": return parseMap(r, node, tag) default: return parseScalar(r, node, tag) } } // parseStruct deserializes a structure and its fields from an XMLNode. Any nested // types in the structure will also be deserialized. func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { t := r.Type() if r.Kind() == reflect.Ptr { if r.IsNil() { // create the structure if it's nil s := reflect.New(r.Type().Elem()) r.Set(s) r = s } r = r.Elem() t = t.Elem() } // unwrap any payloads if payload := tag.Get("payload"); payload != "" { field, _ := t.FieldByName(payload) return parseStruct(r.FieldByName(payload), node, field.Tag) } for i := 0; i < t.NumField(); i++ { field := t.Field(i) if c := field.Name[0:1]; strings.ToLower(c) == c { continue // ignore unexported fields } // figure out what this field is called name := field.Name if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" { name = field.Tag.Get("locationNameList") } else if locName := field.Tag.Get("locationName"); locName != "" { name = locName } // try to find the field by name in elements elems := node.Children[name] if elems == nil { // try to find the field in attributes for _, a := range node.Attr { if name == a.Name.Local { // turn this into a text node for de-serializing elems = []*XMLNode{{Text: a.Value}} } } } member := r.FieldByName(field.Name) for _, elem := range elems { err := parse(member, elem, field.Tag) if err != nil { return err } } } return nil } // parseList deserializes a list of values from an XML node. Each list entry // will also be deserialized. func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { t := r.Type() if tag.Get("flattened") == "" { // look at all item entries mname := "member" if name := tag.Get("locationNameList"); name != "" { mname = name } if Children, ok := node.Children[mname]; ok { if r.IsNil() { r.Set(reflect.MakeSlice(t, len(Children), len(Children))) } for i, c := range Children { err := parse(r.Index(i), c, "") if err != nil { return err } } } } else { // flattened list means this is a single element if r.IsNil() { r.Set(reflect.MakeSlice(t, 0, 0)) } childR := reflect.Zero(t.Elem()) r.Set(reflect.Append(r, childR)) err := parse(r.Index(r.Len()-1), node, "") if err != nil { return err } } return nil } // parseMap deserializes a map from an XMLNode. The direct children of the XMLNode // will also be deserialized as map entries. func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { if r.IsNil() { r.Set(reflect.MakeMap(r.Type())) } if tag.Get("flattened") == "" { // look at all child entries for _, entry := range node.Children["entry"] { parseMapEntry(r, entry, tag) } } else { // this element is itself an entry parseMapEntry(r, node, tag) } return nil } // parseMapEntry deserializes a map entry from a XML node. func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { kname, vname := "key", "value" if n := tag.Get("locationNameKey"); n != "" { kname = n } if n := tag.Get("locationNameValue"); n != "" { vname = n } keys, ok := node.Children[kname] values := node.Children[vname] if ok { for i, key := range keys { keyR := reflect.ValueOf(key.Text) value := values[i] valueR := reflect.New(r.Type().Elem()).Elem() parse(valueR, value, "") r.SetMapIndex(keyR, valueR) } } return nil } // parseScaller deserializes an XMLNode value into a concrete type based on the // interface type of r. // // Error is returned if the deserialization fails due to invalid type conversion, // or unsupported interface type. func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { switch r.Interface().(type) { case *string: r.Set(reflect.ValueOf(&node.Text)) return nil case []byte: b, err := base64.StdEncoding.DecodeString(node.Text) if err != nil { return err } r.Set(reflect.ValueOf(b)) case *bool: v, err := strconv.ParseBool(node.Text) if err != nil { return err } r.Set(reflect.ValueOf(&v)) case *int64: v, err := strconv.ParseInt(node.Text, 10, 64) if err != nil { return err } r.Set(reflect.ValueOf(&v)) case *float64: v, err := strconv.ParseFloat(node.Text, 64) if err != nil { return err } r.Set(reflect.ValueOf(&v)) case *time.Time: const ISO8601UTC = "2006-01-02T15:04:05Z" t, err := time.Parse(ISO8601UTC, node.Text) if err != nil { return err } r.Set(reflect.ValueOf(&t)) default: return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type()) } return nil } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go ================================================ package xmlutil import ( "encoding/xml" "io" "sort" ) // A XMLNode contains the values to be encoded or decoded. type XMLNode struct { Name xml.Name `json:",omitempty"` Children map[string][]*XMLNode `json:",omitempty"` Text string `json:",omitempty"` Attr []xml.Attr `json:",omitempty"` } // NewXMLElement returns a pointer to a new XMLNode initialized to default values. func NewXMLElement(name xml.Name) *XMLNode { return &XMLNode{ Name: name, Children: map[string][]*XMLNode{}, Attr: []xml.Attr{}, } } // AddChild adds child to the XMLNode. func (n *XMLNode) AddChild(child *XMLNode) { if _, ok := n.Children[child.Name.Local]; !ok { n.Children[child.Name.Local] = []*XMLNode{} } n.Children[child.Name.Local] = append(n.Children[child.Name.Local], child) } // XMLToStruct converts a xml.Decoder stream to XMLNode with nested values. func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) { out := &XMLNode{} for { tok, err := d.Token() if tok == nil || err == io.EOF { break } if err != nil { return out, err } switch typed := tok.(type) { case xml.CharData: out.Text = string(typed.Copy()) case xml.StartElement: el := typed.Copy() out.Attr = el.Attr if out.Children == nil { out.Children = map[string][]*XMLNode{} } name := typed.Name.Local slice := out.Children[name] if slice == nil { slice = []*XMLNode{} } node, e := XMLToStruct(d, &el) if e != nil { return out, e } node.Name = typed.Name slice = append(slice, node) out.Children[name] = slice case xml.EndElement: if s != nil && s.Name.Local == typed.Name.Local { // matching end token return out, nil } } } return out, nil } // StructToXML writes an XMLNode to a xml.Encoder as tokens. func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error { e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr}) if node.Text != "" { e.EncodeToken(xml.CharData([]byte(node.Text))) } else if sorted { sortedNames := []string{} for k := range node.Children { sortedNames = append(sortedNames, k) } sort.Strings(sortedNames) for _, k := range sortedNames { for _, v := range node.Children[k] { StructToXML(e, v, sorted) } } } else { for _, c := range node.Children { for _, v := range c { StructToXML(e, v, sorted) } } } e.EncodeToken(xml.EndElement{Name: node.Name}) return e.Flush() } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/service/cloudwatchlogs/api.go ================================================ // THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. // Package cloudwatchlogs provides a client for Amazon CloudWatch Logs. package cloudwatchlogs import ( "fmt" "github.com/aws/aws-sdk-go/aws/awsutil" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/private/protocol" "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" ) const opCancelExportTask = "CancelExportTask" // CancelExportTaskRequest generates a "aws/request.Request" representing the // client's request for the CancelExportTask operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the CancelExportTask method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the CancelExportTaskRequest method. // req, resp := client.CancelExportTaskRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) CancelExportTaskRequest(input *CancelExportTaskInput) (req *request.Request, output *CancelExportTaskOutput) { op := &request.Operation{ Name: opCancelExportTask, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &CancelExportTaskInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &CancelExportTaskOutput{} req.Data = output return } // Cancels an export task if it is in PENDING or RUNNING state. func (c *CloudWatchLogs) CancelExportTask(input *CancelExportTaskInput) (*CancelExportTaskOutput, error) { req, out := c.CancelExportTaskRequest(input) err := req.Send() return out, err } const opCreateExportTask = "CreateExportTask" // CreateExportTaskRequest generates a "aws/request.Request" representing the // client's request for the CreateExportTask operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the CreateExportTask method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the CreateExportTaskRequest method. // req, resp := client.CreateExportTaskRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) CreateExportTaskRequest(input *CreateExportTaskInput) (req *request.Request, output *CreateExportTaskOutput) { op := &request.Operation{ Name: opCreateExportTask, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &CreateExportTaskInput{} } req = c.newRequest(op, input, output) output = &CreateExportTaskOutput{} req.Data = output return } // Creates an ExportTask which allows you to efficiently export data from a // Log Group to your Amazon S3 bucket. // // This is an asynchronous call. If all the required information is provided, // this API will initiate an export task and respond with the task Id. Once // started, DescribeExportTasks can be used to get the status of an export task. // You can only have one active (RUNNING or PENDING) export task at a time, // per account. // // You can export logs from multiple log groups or multiple time ranges to // the same Amazon S3 bucket. To separate out log data for each export task, // you can specify a prefix that will be used as the Amazon S3 key prefix for // all exported objects. func (c *CloudWatchLogs) CreateExportTask(input *CreateExportTaskInput) (*CreateExportTaskOutput, error) { req, out := c.CreateExportTaskRequest(input) err := req.Send() return out, err } const opCreateLogGroup = "CreateLogGroup" // CreateLogGroupRequest generates a "aws/request.Request" representing the // client's request for the CreateLogGroup operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the CreateLogGroup method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the CreateLogGroupRequest method. // req, resp := client.CreateLogGroupRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) CreateLogGroupRequest(input *CreateLogGroupInput) (req *request.Request, output *CreateLogGroupOutput) { op := &request.Operation{ Name: opCreateLogGroup, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &CreateLogGroupInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &CreateLogGroupOutput{} req.Data = output return } // Creates a new log group with the specified name. The name of the log group // must be unique within a region for an AWS account. You can create up to 500 // log groups per account. // // You must use the following guidelines when naming a log group: // // Log group names can be between 1 and 512 characters long. // // Allowed characters are a-z, A-Z, 0-9, '_' (underscore), '-' (hyphen), // '/' (forward slash), and '.' (period). func (c *CloudWatchLogs) CreateLogGroup(input *CreateLogGroupInput) (*CreateLogGroupOutput, error) { req, out := c.CreateLogGroupRequest(input) err := req.Send() return out, err } const opCreateLogStream = "CreateLogStream" // CreateLogStreamRequest generates a "aws/request.Request" representing the // client's request for the CreateLogStream operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the CreateLogStream method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the CreateLogStreamRequest method. // req, resp := client.CreateLogStreamRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) CreateLogStreamRequest(input *CreateLogStreamInput) (req *request.Request, output *CreateLogStreamOutput) { op := &request.Operation{ Name: opCreateLogStream, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &CreateLogStreamInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &CreateLogStreamOutput{} req.Data = output return } // Creates a new log stream in the specified log group. The name of the log // stream must be unique within the log group. There is no limit on the number // of log streams that can exist in a log group. // // You must use the following guidelines when naming a log stream: // // Log stream names can be between 1 and 512 characters long. // // The ':' colon character is not allowed. func (c *CloudWatchLogs) CreateLogStream(input *CreateLogStreamInput) (*CreateLogStreamOutput, error) { req, out := c.CreateLogStreamRequest(input) err := req.Send() return out, err } const opDeleteDestination = "DeleteDestination" // DeleteDestinationRequest generates a "aws/request.Request" representing the // client's request for the DeleteDestination operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DeleteDestination method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DeleteDestinationRequest method. // req, resp := client.DeleteDestinationRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DeleteDestinationRequest(input *DeleteDestinationInput) (req *request.Request, output *DeleteDestinationOutput) { op := &request.Operation{ Name: opDeleteDestination, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &DeleteDestinationInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &DeleteDestinationOutput{} req.Data = output return } // Deletes the destination with the specified name and eventually disables all // the subscription filters that publish to it. This will not delete the physical // resource encapsulated by the destination. func (c *CloudWatchLogs) DeleteDestination(input *DeleteDestinationInput) (*DeleteDestinationOutput, error) { req, out := c.DeleteDestinationRequest(input) err := req.Send() return out, err } const opDeleteLogGroup = "DeleteLogGroup" // DeleteLogGroupRequest generates a "aws/request.Request" representing the // client's request for the DeleteLogGroup operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DeleteLogGroup method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DeleteLogGroupRequest method. // req, resp := client.DeleteLogGroupRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DeleteLogGroupRequest(input *DeleteLogGroupInput) (req *request.Request, output *DeleteLogGroupOutput) { op := &request.Operation{ Name: opDeleteLogGroup, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &DeleteLogGroupInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &DeleteLogGroupOutput{} req.Data = output return } // Deletes the log group with the specified name and permanently deletes all // the archived log events associated with it. func (c *CloudWatchLogs) DeleteLogGroup(input *DeleteLogGroupInput) (*DeleteLogGroupOutput, error) { req, out := c.DeleteLogGroupRequest(input) err := req.Send() return out, err } const opDeleteLogStream = "DeleteLogStream" // DeleteLogStreamRequest generates a "aws/request.Request" representing the // client's request for the DeleteLogStream operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DeleteLogStream method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DeleteLogStreamRequest method. // req, resp := client.DeleteLogStreamRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DeleteLogStreamRequest(input *DeleteLogStreamInput) (req *request.Request, output *DeleteLogStreamOutput) { op := &request.Operation{ Name: opDeleteLogStream, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &DeleteLogStreamInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &DeleteLogStreamOutput{} req.Data = output return } // Deletes a log stream and permanently deletes all the archived log events // associated with it. func (c *CloudWatchLogs) DeleteLogStream(input *DeleteLogStreamInput) (*DeleteLogStreamOutput, error) { req, out := c.DeleteLogStreamRequest(input) err := req.Send() return out, err } const opDeleteMetricFilter = "DeleteMetricFilter" // DeleteMetricFilterRequest generates a "aws/request.Request" representing the // client's request for the DeleteMetricFilter operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DeleteMetricFilter method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DeleteMetricFilterRequest method. // req, resp := client.DeleteMetricFilterRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DeleteMetricFilterRequest(input *DeleteMetricFilterInput) (req *request.Request, output *DeleteMetricFilterOutput) { op := &request.Operation{ Name: opDeleteMetricFilter, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &DeleteMetricFilterInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &DeleteMetricFilterOutput{} req.Data = output return } // Deletes a metric filter associated with the specified log group. func (c *CloudWatchLogs) DeleteMetricFilter(input *DeleteMetricFilterInput) (*DeleteMetricFilterOutput, error) { req, out := c.DeleteMetricFilterRequest(input) err := req.Send() return out, err } const opDeleteRetentionPolicy = "DeleteRetentionPolicy" // DeleteRetentionPolicyRequest generates a "aws/request.Request" representing the // client's request for the DeleteRetentionPolicy operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DeleteRetentionPolicy method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DeleteRetentionPolicyRequest method. // req, resp := client.DeleteRetentionPolicyRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DeleteRetentionPolicyRequest(input *DeleteRetentionPolicyInput) (req *request.Request, output *DeleteRetentionPolicyOutput) { op := &request.Operation{ Name: opDeleteRetentionPolicy, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &DeleteRetentionPolicyInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &DeleteRetentionPolicyOutput{} req.Data = output return } // Deletes the retention policy of the specified log group. Log events would // not expire if they belong to log groups without a retention policy. func (c *CloudWatchLogs) DeleteRetentionPolicy(input *DeleteRetentionPolicyInput) (*DeleteRetentionPolicyOutput, error) { req, out := c.DeleteRetentionPolicyRequest(input) err := req.Send() return out, err } const opDeleteSubscriptionFilter = "DeleteSubscriptionFilter" // DeleteSubscriptionFilterRequest generates a "aws/request.Request" representing the // client's request for the DeleteSubscriptionFilter operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DeleteSubscriptionFilter method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DeleteSubscriptionFilterRequest method. // req, resp := client.DeleteSubscriptionFilterRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DeleteSubscriptionFilterRequest(input *DeleteSubscriptionFilterInput) (req *request.Request, output *DeleteSubscriptionFilterOutput) { op := &request.Operation{ Name: opDeleteSubscriptionFilter, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &DeleteSubscriptionFilterInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &DeleteSubscriptionFilterOutput{} req.Data = output return } // Deletes a subscription filter associated with the specified log group. func (c *CloudWatchLogs) DeleteSubscriptionFilter(input *DeleteSubscriptionFilterInput) (*DeleteSubscriptionFilterOutput, error) { req, out := c.DeleteSubscriptionFilterRequest(input) err := req.Send() return out, err } const opDescribeDestinations = "DescribeDestinations" // DescribeDestinationsRequest generates a "aws/request.Request" representing the // client's request for the DescribeDestinations operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DescribeDestinations method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DescribeDestinationsRequest method. // req, resp := client.DescribeDestinationsRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DescribeDestinationsRequest(input *DescribeDestinationsInput) (req *request.Request, output *DescribeDestinationsOutput) { op := &request.Operation{ Name: opDescribeDestinations, HTTPMethod: "POST", HTTPPath: "/", Paginator: &request.Paginator{ InputTokens: []string{"nextToken"}, OutputTokens: []string{"nextToken"}, LimitToken: "limit", TruncationToken: "", }, } if input == nil { input = &DescribeDestinationsInput{} } req = c.newRequest(op, input, output) output = &DescribeDestinationsOutput{} req.Data = output return } // Returns all the destinations that are associated with the AWS account making // the request. The list returned in the response is ASCII-sorted by destination // name. // // By default, this operation returns up to 50 destinations. If there are more // destinations to list, the response would contain a nextToken value in the // response body. You can also limit the number of destinations returned in // the response by specifying the limit parameter in the request. func (c *CloudWatchLogs) DescribeDestinations(input *DescribeDestinationsInput) (*DescribeDestinationsOutput, error) { req, out := c.DescribeDestinationsRequest(input) err := req.Send() return out, err } // DescribeDestinationsPages iterates over the pages of a DescribeDestinations operation, // calling the "fn" function with the response data for each page. To stop // iterating, return false from the fn function. // // See DescribeDestinations method for more information on how to use this operation. // // Note: This operation can generate multiple requests to a service. // // // Example iterating over at most 3 pages of a DescribeDestinations operation. // pageNum := 0 // err := client.DescribeDestinationsPages(params, // func(page *DescribeDestinationsOutput, lastPage bool) bool { // pageNum++ // fmt.Println(page) // return pageNum <= 3 // }) // func (c *CloudWatchLogs) DescribeDestinationsPages(input *DescribeDestinationsInput, fn func(p *DescribeDestinationsOutput, lastPage bool) (shouldContinue bool)) error { page, _ := c.DescribeDestinationsRequest(input) page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator")) return page.EachPage(func(p interface{}, lastPage bool) bool { return fn(p.(*DescribeDestinationsOutput), lastPage) }) } const opDescribeExportTasks = "DescribeExportTasks" // DescribeExportTasksRequest generates a "aws/request.Request" representing the // client's request for the DescribeExportTasks operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DescribeExportTasks method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DescribeExportTasksRequest method. // req, resp := client.DescribeExportTasksRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DescribeExportTasksRequest(input *DescribeExportTasksInput) (req *request.Request, output *DescribeExportTasksOutput) { op := &request.Operation{ Name: opDescribeExportTasks, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &DescribeExportTasksInput{} } req = c.newRequest(op, input, output) output = &DescribeExportTasksOutput{} req.Data = output return } // Returns all the export tasks that are associated with the AWS account making // the request. The export tasks can be filtered based on TaskId or TaskStatus. // // By default, this operation returns up to 50 export tasks that satisfy the // specified filters. If there are more export tasks to list, the response would // contain a nextToken value in the response body. You can also limit the number // of export tasks returned in the response by specifying the limit parameter // in the request. func (c *CloudWatchLogs) DescribeExportTasks(input *DescribeExportTasksInput) (*DescribeExportTasksOutput, error) { req, out := c.DescribeExportTasksRequest(input) err := req.Send() return out, err } const opDescribeLogGroups = "DescribeLogGroups" // DescribeLogGroupsRequest generates a "aws/request.Request" representing the // client's request for the DescribeLogGroups operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DescribeLogGroups method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DescribeLogGroupsRequest method. // req, resp := client.DescribeLogGroupsRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DescribeLogGroupsRequest(input *DescribeLogGroupsInput) (req *request.Request, output *DescribeLogGroupsOutput) { op := &request.Operation{ Name: opDescribeLogGroups, HTTPMethod: "POST", HTTPPath: "/", Paginator: &request.Paginator{ InputTokens: []string{"nextToken"}, OutputTokens: []string{"nextToken"}, LimitToken: "limit", TruncationToken: "", }, } if input == nil { input = &DescribeLogGroupsInput{} } req = c.newRequest(op, input, output) output = &DescribeLogGroupsOutput{} req.Data = output return } // Returns all the log groups that are associated with the AWS account making // the request. The list returned in the response is ASCII-sorted by log group // name. // // By default, this operation returns up to 50 log groups. If there are more // log groups to list, the response would contain a nextToken value in the response // body. You can also limit the number of log groups returned in the response // by specifying the limit parameter in the request. func (c *CloudWatchLogs) DescribeLogGroups(input *DescribeLogGroupsInput) (*DescribeLogGroupsOutput, error) { req, out := c.DescribeLogGroupsRequest(input) err := req.Send() return out, err } // DescribeLogGroupsPages iterates over the pages of a DescribeLogGroups operation, // calling the "fn" function with the response data for each page. To stop // iterating, return false from the fn function. // // See DescribeLogGroups method for more information on how to use this operation. // // Note: This operation can generate multiple requests to a service. // // // Example iterating over at most 3 pages of a DescribeLogGroups operation. // pageNum := 0 // err := client.DescribeLogGroupsPages(params, // func(page *DescribeLogGroupsOutput, lastPage bool) bool { // pageNum++ // fmt.Println(page) // return pageNum <= 3 // }) // func (c *CloudWatchLogs) DescribeLogGroupsPages(input *DescribeLogGroupsInput, fn func(p *DescribeLogGroupsOutput, lastPage bool) (shouldContinue bool)) error { page, _ := c.DescribeLogGroupsRequest(input) page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator")) return page.EachPage(func(p interface{}, lastPage bool) bool { return fn(p.(*DescribeLogGroupsOutput), lastPage) }) } const opDescribeLogStreams = "DescribeLogStreams" // DescribeLogStreamsRequest generates a "aws/request.Request" representing the // client's request for the DescribeLogStreams operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DescribeLogStreams method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DescribeLogStreamsRequest method. // req, resp := client.DescribeLogStreamsRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DescribeLogStreamsRequest(input *DescribeLogStreamsInput) (req *request.Request, output *DescribeLogStreamsOutput) { op := &request.Operation{ Name: opDescribeLogStreams, HTTPMethod: "POST", HTTPPath: "/", Paginator: &request.Paginator{ InputTokens: []string{"nextToken"}, OutputTokens: []string{"nextToken"}, LimitToken: "limit", TruncationToken: "", }, } if input == nil { input = &DescribeLogStreamsInput{} } req = c.newRequest(op, input, output) output = &DescribeLogStreamsOutput{} req.Data = output return } // Returns all the log streams that are associated with the specified log group. // The list returned in the response is ASCII-sorted by log stream name. // // By default, this operation returns up to 50 log streams. If there are more // log streams to list, the response would contain a nextToken value in the // response body. You can also limit the number of log streams returned in the // response by specifying the limit parameter in the request. This operation // has a limit of five transactions per second, after which transactions are // throttled. func (c *CloudWatchLogs) DescribeLogStreams(input *DescribeLogStreamsInput) (*DescribeLogStreamsOutput, error) { req, out := c.DescribeLogStreamsRequest(input) err := req.Send() return out, err } // DescribeLogStreamsPages iterates over the pages of a DescribeLogStreams operation, // calling the "fn" function with the response data for each page. To stop // iterating, return false from the fn function. // // See DescribeLogStreams method for more information on how to use this operation. // // Note: This operation can generate multiple requests to a service. // // // Example iterating over at most 3 pages of a DescribeLogStreams operation. // pageNum := 0 // err := client.DescribeLogStreamsPages(params, // func(page *DescribeLogStreamsOutput, lastPage bool) bool { // pageNum++ // fmt.Println(page) // return pageNum <= 3 // }) // func (c *CloudWatchLogs) DescribeLogStreamsPages(input *DescribeLogStreamsInput, fn func(p *DescribeLogStreamsOutput, lastPage bool) (shouldContinue bool)) error { page, _ := c.DescribeLogStreamsRequest(input) page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator")) return page.EachPage(func(p interface{}, lastPage bool) bool { return fn(p.(*DescribeLogStreamsOutput), lastPage) }) } const opDescribeMetricFilters = "DescribeMetricFilters" // DescribeMetricFiltersRequest generates a "aws/request.Request" representing the // client's request for the DescribeMetricFilters operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DescribeMetricFilters method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DescribeMetricFiltersRequest method. // req, resp := client.DescribeMetricFiltersRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DescribeMetricFiltersRequest(input *DescribeMetricFiltersInput) (req *request.Request, output *DescribeMetricFiltersOutput) { op := &request.Operation{ Name: opDescribeMetricFilters, HTTPMethod: "POST", HTTPPath: "/", Paginator: &request.Paginator{ InputTokens: []string{"nextToken"}, OutputTokens: []string{"nextToken"}, LimitToken: "limit", TruncationToken: "", }, } if input == nil { input = &DescribeMetricFiltersInput{} } req = c.newRequest(op, input, output) output = &DescribeMetricFiltersOutput{} req.Data = output return } // Returns all the metrics filters associated with the specified log group. // The list returned in the response is ASCII-sorted by filter name. // // By default, this operation returns up to 50 metric filters. If there are // more metric filters to list, the response would contain a nextToken value // in the response body. You can also limit the number of metric filters returned // in the response by specifying the limit parameter in the request. func (c *CloudWatchLogs) DescribeMetricFilters(input *DescribeMetricFiltersInput) (*DescribeMetricFiltersOutput, error) { req, out := c.DescribeMetricFiltersRequest(input) err := req.Send() return out, err } // DescribeMetricFiltersPages iterates over the pages of a DescribeMetricFilters operation, // calling the "fn" function with the response data for each page. To stop // iterating, return false from the fn function. // // See DescribeMetricFilters method for more information on how to use this operation. // // Note: This operation can generate multiple requests to a service. // // // Example iterating over at most 3 pages of a DescribeMetricFilters operation. // pageNum := 0 // err := client.DescribeMetricFiltersPages(params, // func(page *DescribeMetricFiltersOutput, lastPage bool) bool { // pageNum++ // fmt.Println(page) // return pageNum <= 3 // }) // func (c *CloudWatchLogs) DescribeMetricFiltersPages(input *DescribeMetricFiltersInput, fn func(p *DescribeMetricFiltersOutput, lastPage bool) (shouldContinue bool)) error { page, _ := c.DescribeMetricFiltersRequest(input) page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator")) return page.EachPage(func(p interface{}, lastPage bool) bool { return fn(p.(*DescribeMetricFiltersOutput), lastPage) }) } const opDescribeSubscriptionFilters = "DescribeSubscriptionFilters" // DescribeSubscriptionFiltersRequest generates a "aws/request.Request" representing the // client's request for the DescribeSubscriptionFilters operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DescribeSubscriptionFilters method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DescribeSubscriptionFiltersRequest method. // req, resp := client.DescribeSubscriptionFiltersRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) DescribeSubscriptionFiltersRequest(input *DescribeSubscriptionFiltersInput) (req *request.Request, output *DescribeSubscriptionFiltersOutput) { op := &request.Operation{ Name: opDescribeSubscriptionFilters, HTTPMethod: "POST", HTTPPath: "/", Paginator: &request.Paginator{ InputTokens: []string{"nextToken"}, OutputTokens: []string{"nextToken"}, LimitToken: "limit", TruncationToken: "", }, } if input == nil { input = &DescribeSubscriptionFiltersInput{} } req = c.newRequest(op, input, output) output = &DescribeSubscriptionFiltersOutput{} req.Data = output return } // Returns all the subscription filters associated with the specified log group. // The list returned in the response is ASCII-sorted by filter name. // // By default, this operation returns up to 50 subscription filters. If there // are more subscription filters to list, the response would contain a nextToken // value in the response body. You can also limit the number of subscription // filters returned in the response by specifying the limit parameter in the // request. func (c *CloudWatchLogs) DescribeSubscriptionFilters(input *DescribeSubscriptionFiltersInput) (*DescribeSubscriptionFiltersOutput, error) { req, out := c.DescribeSubscriptionFiltersRequest(input) err := req.Send() return out, err } // DescribeSubscriptionFiltersPages iterates over the pages of a DescribeSubscriptionFilters operation, // calling the "fn" function with the response data for each page. To stop // iterating, return false from the fn function. // // See DescribeSubscriptionFilters method for more information on how to use this operation. // // Note: This operation can generate multiple requests to a service. // // // Example iterating over at most 3 pages of a DescribeSubscriptionFilters operation. // pageNum := 0 // err := client.DescribeSubscriptionFiltersPages(params, // func(page *DescribeSubscriptionFiltersOutput, lastPage bool) bool { // pageNum++ // fmt.Println(page) // return pageNum <= 3 // }) // func (c *CloudWatchLogs) DescribeSubscriptionFiltersPages(input *DescribeSubscriptionFiltersInput, fn func(p *DescribeSubscriptionFiltersOutput, lastPage bool) (shouldContinue bool)) error { page, _ := c.DescribeSubscriptionFiltersRequest(input) page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator")) return page.EachPage(func(p interface{}, lastPage bool) bool { return fn(p.(*DescribeSubscriptionFiltersOutput), lastPage) }) } const opFilterLogEvents = "FilterLogEvents" // FilterLogEventsRequest generates a "aws/request.Request" representing the // client's request for the FilterLogEvents operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the FilterLogEvents method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the FilterLogEventsRequest method. // req, resp := client.FilterLogEventsRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) FilterLogEventsRequest(input *FilterLogEventsInput) (req *request.Request, output *FilterLogEventsOutput) { op := &request.Operation{ Name: opFilterLogEvents, HTTPMethod: "POST", HTTPPath: "/", Paginator: &request.Paginator{ InputTokens: []string{"nextToken"}, OutputTokens: []string{"nextToken"}, LimitToken: "limit", TruncationToken: "", }, } if input == nil { input = &FilterLogEventsInput{} } req = c.newRequest(op, input, output) output = &FilterLogEventsOutput{} req.Data = output return } // Retrieves log events, optionally filtered by a filter pattern from the specified // log group. You can provide an optional time range to filter the results on // the event timestamp. You can limit the streams searched to an explicit list // of logStreamNames. // // By default, this operation returns as much matching log events as can fit // in a response size of 1MB, up to 10,000 log events, or all the events found // within a time-bounded scan window. If the response includes a nextToken, // then there is more data to search, and the search can be resumed with a new // request providing the nextToken. The response will contain a list of searchedLogStreams // that contains information about which streams were searched in the request // and whether they have been searched completely or require further pagination. // The limit parameter in the request can be used to specify the maximum number // of events to return in a page. func (c *CloudWatchLogs) FilterLogEvents(input *FilterLogEventsInput) (*FilterLogEventsOutput, error) { req, out := c.FilterLogEventsRequest(input) err := req.Send() return out, err } // FilterLogEventsPages iterates over the pages of a FilterLogEvents operation, // calling the "fn" function with the response data for each page. To stop // iterating, return false from the fn function. // // See FilterLogEvents method for more information on how to use this operation. // // Note: This operation can generate multiple requests to a service. // // // Example iterating over at most 3 pages of a FilterLogEvents operation. // pageNum := 0 // err := client.FilterLogEventsPages(params, // func(page *FilterLogEventsOutput, lastPage bool) bool { // pageNum++ // fmt.Println(page) // return pageNum <= 3 // }) // func (c *CloudWatchLogs) FilterLogEventsPages(input *FilterLogEventsInput, fn func(p *FilterLogEventsOutput, lastPage bool) (shouldContinue bool)) error { page, _ := c.FilterLogEventsRequest(input) page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator")) return page.EachPage(func(p interface{}, lastPage bool) bool { return fn(p.(*FilterLogEventsOutput), lastPage) }) } const opGetLogEvents = "GetLogEvents" // GetLogEventsRequest generates a "aws/request.Request" representing the // client's request for the GetLogEvents operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the GetLogEvents method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the GetLogEventsRequest method. // req, resp := client.GetLogEventsRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) GetLogEventsRequest(input *GetLogEventsInput) (req *request.Request, output *GetLogEventsOutput) { op := &request.Operation{ Name: opGetLogEvents, HTTPMethod: "POST", HTTPPath: "/", Paginator: &request.Paginator{ InputTokens: []string{"nextToken"}, OutputTokens: []string{"nextForwardToken"}, LimitToken: "limit", TruncationToken: "", }, } if input == nil { input = &GetLogEventsInput{} } req = c.newRequest(op, input, output) output = &GetLogEventsOutput{} req.Data = output return } // Retrieves log events from the specified log stream. You can provide an optional // time range to filter the results on the event timestamp. // // By default, this operation returns as much log events as can fit in a response // size of 1MB, up to 10,000 log events. The response will always include a // nextForwardToken and a nextBackwardToken in the response body. You can use // any of these tokens in subsequent GetLogEvents requests to paginate through // events in either forward or backward direction. You can also limit the number // of log events returned in the response by specifying the limit parameter // in the request. func (c *CloudWatchLogs) GetLogEvents(input *GetLogEventsInput) (*GetLogEventsOutput, error) { req, out := c.GetLogEventsRequest(input) err := req.Send() return out, err } // GetLogEventsPages iterates over the pages of a GetLogEvents operation, // calling the "fn" function with the response data for each page. To stop // iterating, return false from the fn function. // // See GetLogEvents method for more information on how to use this operation. // // Note: This operation can generate multiple requests to a service. // // // Example iterating over at most 3 pages of a GetLogEvents operation. // pageNum := 0 // err := client.GetLogEventsPages(params, // func(page *GetLogEventsOutput, lastPage bool) bool { // pageNum++ // fmt.Println(page) // return pageNum <= 3 // }) // func (c *CloudWatchLogs) GetLogEventsPages(input *GetLogEventsInput, fn func(p *GetLogEventsOutput, lastPage bool) (shouldContinue bool)) error { page, _ := c.GetLogEventsRequest(input) page.Handlers.Build.PushBack(request.MakeAddToUserAgentFreeFormHandler("Paginator")) return page.EachPage(func(p interface{}, lastPage bool) bool { return fn(p.(*GetLogEventsOutput), lastPage) }) } const opPutDestination = "PutDestination" // PutDestinationRequest generates a "aws/request.Request" representing the // client's request for the PutDestination operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the PutDestination method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the PutDestinationRequest method. // req, resp := client.PutDestinationRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) PutDestinationRequest(input *PutDestinationInput) (req *request.Request, output *PutDestinationOutput) { op := &request.Operation{ Name: opPutDestination, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &PutDestinationInput{} } req = c.newRequest(op, input, output) output = &PutDestinationOutput{} req.Data = output return } // Creates or updates a Destination. A destination encapsulates a physical resource // (such as a Kinesis stream) and allows you to subscribe to a real-time stream // of log events of a different account, ingested through PutLogEvents requests. // Currently, the only supported physical resource is a Amazon Kinesis stream // belonging to the same account as the destination. // // A destination controls what is written to its Amazon Kinesis stream through // an access policy. By default, PutDestination does not set any access policy // with the destination, which means a cross-account user will not be able to // call PutSubscriptionFilter against this destination. To enable that, the // destination owner must call PutDestinationPolicy after PutDestination. func (c *CloudWatchLogs) PutDestination(input *PutDestinationInput) (*PutDestinationOutput, error) { req, out := c.PutDestinationRequest(input) err := req.Send() return out, err } const opPutDestinationPolicy = "PutDestinationPolicy" // PutDestinationPolicyRequest generates a "aws/request.Request" representing the // client's request for the PutDestinationPolicy operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the PutDestinationPolicy method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the PutDestinationPolicyRequest method. // req, resp := client.PutDestinationPolicyRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) PutDestinationPolicyRequest(input *PutDestinationPolicyInput) (req *request.Request, output *PutDestinationPolicyOutput) { op := &request.Operation{ Name: opPutDestinationPolicy, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &PutDestinationPolicyInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &PutDestinationPolicyOutput{} req.Data = output return } // Creates or updates an access policy associated with an existing Destination. // An access policy is an IAM policy document (http://docs.aws.amazon.com/IAM/latest/UserGuide/policies_overview.html) // that is used to authorize claims to register a subscription filter against // a given destination. func (c *CloudWatchLogs) PutDestinationPolicy(input *PutDestinationPolicyInput) (*PutDestinationPolicyOutput, error) { req, out := c.PutDestinationPolicyRequest(input) err := req.Send() return out, err } const opPutLogEvents = "PutLogEvents" // PutLogEventsRequest generates a "aws/request.Request" representing the // client's request for the PutLogEvents operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the PutLogEvents method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the PutLogEventsRequest method. // req, resp := client.PutLogEventsRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) PutLogEventsRequest(input *PutLogEventsInput) (req *request.Request, output *PutLogEventsOutput) { op := &request.Operation{ Name: opPutLogEvents, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &PutLogEventsInput{} } req = c.newRequest(op, input, output) output = &PutLogEventsOutput{} req.Data = output return } // Uploads a batch of log events to the specified log stream. // // Every PutLogEvents request must include the sequenceToken obtained from // the response of the previous request. An upload in a newly created log stream // does not require a sequenceToken. You can also get the sequenceToken using // DescribeLogStreams. // // The batch of events must satisfy the following constraints: // // The maximum batch size is 1,048,576 bytes, and this size is calculated // as the sum of all event messages in UTF-8, plus 26 bytes for each log event. // // None of the log events in the batch can be more than 2 hours in the future. // // None of the log events in the batch can be older than 14 days or the retention // period of the log group. // // The log events in the batch must be in chronological ordered by their // timestamp. // // The maximum number of log events in a batch is 10,000. // // A batch of log events in a single PutLogEvents request cannot span more // than 24 hours. Otherwise, the PutLogEvents operation will fail. func (c *CloudWatchLogs) PutLogEvents(input *PutLogEventsInput) (*PutLogEventsOutput, error) { req, out := c.PutLogEventsRequest(input) err := req.Send() return out, err } const opPutMetricFilter = "PutMetricFilter" // PutMetricFilterRequest generates a "aws/request.Request" representing the // client's request for the PutMetricFilter operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the PutMetricFilter method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the PutMetricFilterRequest method. // req, resp := client.PutMetricFilterRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) PutMetricFilterRequest(input *PutMetricFilterInput) (req *request.Request, output *PutMetricFilterOutput) { op := &request.Operation{ Name: opPutMetricFilter, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &PutMetricFilterInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &PutMetricFilterOutput{} req.Data = output return } // Creates or updates a metric filter and associates it with the specified log // group. Metric filters allow you to configure rules to extract metric data // from log events ingested through PutLogEvents requests. // // The maximum number of metric filters that can be associated with a log group // is 100. func (c *CloudWatchLogs) PutMetricFilter(input *PutMetricFilterInput) (*PutMetricFilterOutput, error) { req, out := c.PutMetricFilterRequest(input) err := req.Send() return out, err } const opPutRetentionPolicy = "PutRetentionPolicy" // PutRetentionPolicyRequest generates a "aws/request.Request" representing the // client's request for the PutRetentionPolicy operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the PutRetentionPolicy method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the PutRetentionPolicyRequest method. // req, resp := client.PutRetentionPolicyRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) PutRetentionPolicyRequest(input *PutRetentionPolicyInput) (req *request.Request, output *PutRetentionPolicyOutput) { op := &request.Operation{ Name: opPutRetentionPolicy, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &PutRetentionPolicyInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &PutRetentionPolicyOutput{} req.Data = output return } // Sets the retention of the specified log group. A retention policy allows // you to configure the number of days you want to retain log events in the // specified log group. func (c *CloudWatchLogs) PutRetentionPolicy(input *PutRetentionPolicyInput) (*PutRetentionPolicyOutput, error) { req, out := c.PutRetentionPolicyRequest(input) err := req.Send() return out, err } const opPutSubscriptionFilter = "PutSubscriptionFilter" // PutSubscriptionFilterRequest generates a "aws/request.Request" representing the // client's request for the PutSubscriptionFilter operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the PutSubscriptionFilter method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the PutSubscriptionFilterRequest method. // req, resp := client.PutSubscriptionFilterRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) PutSubscriptionFilterRequest(input *PutSubscriptionFilterInput) (req *request.Request, output *PutSubscriptionFilterOutput) { op := &request.Operation{ Name: opPutSubscriptionFilter, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &PutSubscriptionFilterInput{} } req = c.newRequest(op, input, output) req.Handlers.Unmarshal.Remove(jsonrpc.UnmarshalHandler) req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) output = &PutSubscriptionFilterOutput{} req.Data = output return } // Creates or updates a subscription filter and associates it with the specified // log group. Subscription filters allow you to subscribe to a real-time stream // of log events ingested through PutLogEvents requests and have them delivered // to a specific destination. Currently, the supported destinations are: // // An Amazon Kinesis stream belonging to the same account as the subscription // filter, for same-account delivery. // // A logical destination (used via an ARN of Destination) belonging to a // different account, for cross-account delivery. // // An Amazon Kinesis Firehose stream belonging to the same account as the // subscription filter, for same-account delivery. // // An AWS Lambda function belonging to the same account as the subscription // filter, for same-account delivery. // // Currently there can only be one subscription filter associated with a // log group. func (c *CloudWatchLogs) PutSubscriptionFilter(input *PutSubscriptionFilterInput) (*PutSubscriptionFilterOutput, error) { req, out := c.PutSubscriptionFilterRequest(input) err := req.Send() return out, err } const opTestMetricFilter = "TestMetricFilter" // TestMetricFilterRequest generates a "aws/request.Request" representing the // client's request for the TestMetricFilter operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the TestMetricFilter method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the TestMetricFilterRequest method. // req, resp := client.TestMetricFilterRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *CloudWatchLogs) TestMetricFilterRequest(input *TestMetricFilterInput) (req *request.Request, output *TestMetricFilterOutput) { op := &request.Operation{ Name: opTestMetricFilter, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &TestMetricFilterInput{} } req = c.newRequest(op, input, output) output = &TestMetricFilterOutput{} req.Data = output return } // Tests the filter pattern of a metric filter against a sample of log event // messages. You can use this operation to validate the correctness of a metric // filter pattern. func (c *CloudWatchLogs) TestMetricFilter(input *TestMetricFilterInput) (*TestMetricFilterOutput, error) { req, out := c.TestMetricFilterRequest(input) err := req.Send() return out, err } type CancelExportTaskInput struct { _ struct{} `type:"structure"` // Id of the export task to cancel. TaskId *string `locationName:"taskId" min:"1" type:"string" required:"true"` } // String returns the string representation func (s CancelExportTaskInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s CancelExportTaskInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *CancelExportTaskInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "CancelExportTaskInput"} if s.TaskId == nil { invalidParams.Add(request.NewErrParamRequired("TaskId")) } if s.TaskId != nil && len(*s.TaskId) < 1 { invalidParams.Add(request.NewErrParamMinLen("TaskId", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type CancelExportTaskOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s CancelExportTaskOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s CancelExportTaskOutput) GoString() string { return s.String() } type CreateExportTaskInput struct { _ struct{} `type:"structure"` // Name of Amazon S3 bucket to which the log data will be exported. // // Note: Only buckets in the same AWS region are supported. Destination *string `locationName:"destination" min:"1" type:"string" required:"true"` // Prefix that will be used as the start of Amazon S3 key for every object exported. // If not specified, this defaults to 'exportedlogs'. DestinationPrefix *string `locationName:"destinationPrefix" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. It indicates the start time of the range for the request. Events // with a timestamp prior to this time will not be exported. From *int64 `locationName:"from" type:"long" required:"true"` // The name of the log group to export. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // Will only export log streams that match the provided logStreamNamePrefix. // If you don't specify a value, no prefix filter is applied. LogStreamNamePrefix *string `locationName:"logStreamNamePrefix" min:"1" type:"string"` // The name of the export task. TaskName *string `locationName:"taskName" min:"1" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. It indicates the end time of the range for the request. Events // with a timestamp later than this time will not be exported. To *int64 `locationName:"to" type:"long" required:"true"` } // String returns the string representation func (s CreateExportTaskInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s CreateExportTaskInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *CreateExportTaskInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "CreateExportTaskInput"} if s.Destination == nil { invalidParams.Add(request.NewErrParamRequired("Destination")) } if s.Destination != nil && len(*s.Destination) < 1 { invalidParams.Add(request.NewErrParamMinLen("Destination", 1)) } if s.From == nil { invalidParams.Add(request.NewErrParamRequired("From")) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.LogStreamNamePrefix != nil && len(*s.LogStreamNamePrefix) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogStreamNamePrefix", 1)) } if s.TaskName != nil && len(*s.TaskName) < 1 { invalidParams.Add(request.NewErrParamMinLen("TaskName", 1)) } if s.To == nil { invalidParams.Add(request.NewErrParamRequired("To")) } if invalidParams.Len() > 0 { return invalidParams } return nil } type CreateExportTaskOutput struct { _ struct{} `type:"structure"` // Id of the export task that got created. TaskId *string `locationName:"taskId" min:"1" type:"string"` } // String returns the string representation func (s CreateExportTaskOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s CreateExportTaskOutput) GoString() string { return s.String() } type CreateLogGroupInput struct { _ struct{} `type:"structure"` // The name of the log group to create. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s CreateLogGroupInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s CreateLogGroupInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *CreateLogGroupInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "CreateLogGroupInput"} if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type CreateLogGroupOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s CreateLogGroupOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s CreateLogGroupOutput) GoString() string { return s.String() } type CreateLogStreamInput struct { _ struct{} `type:"structure"` // The name of the log group under which the log stream is to be created. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // The name of the log stream to create. LogStreamName *string `locationName:"logStreamName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s CreateLogStreamInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s CreateLogStreamInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *CreateLogStreamInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "CreateLogStreamInput"} if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.LogStreamName == nil { invalidParams.Add(request.NewErrParamRequired("LogStreamName")) } if s.LogStreamName != nil && len(*s.LogStreamName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogStreamName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type CreateLogStreamOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s CreateLogStreamOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s CreateLogStreamOutput) GoString() string { return s.String() } type DeleteDestinationInput struct { _ struct{} `type:"structure"` // The name of destination to delete. DestinationName *string `locationName:"destinationName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s DeleteDestinationInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteDestinationInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DeleteDestinationInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DeleteDestinationInput"} if s.DestinationName == nil { invalidParams.Add(request.NewErrParamRequired("DestinationName")) } if s.DestinationName != nil && len(*s.DestinationName) < 1 { invalidParams.Add(request.NewErrParamMinLen("DestinationName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DeleteDestinationOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s DeleteDestinationOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteDestinationOutput) GoString() string { return s.String() } type DeleteLogGroupInput struct { _ struct{} `type:"structure"` // The name of the log group to delete. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s DeleteLogGroupInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteLogGroupInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DeleteLogGroupInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DeleteLogGroupInput"} if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DeleteLogGroupOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s DeleteLogGroupOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteLogGroupOutput) GoString() string { return s.String() } type DeleteLogStreamInput struct { _ struct{} `type:"structure"` // The name of the log group under which the log stream to delete belongs. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // The name of the log stream to delete. LogStreamName *string `locationName:"logStreamName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s DeleteLogStreamInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteLogStreamInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DeleteLogStreamInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DeleteLogStreamInput"} if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.LogStreamName == nil { invalidParams.Add(request.NewErrParamRequired("LogStreamName")) } if s.LogStreamName != nil && len(*s.LogStreamName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogStreamName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DeleteLogStreamOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s DeleteLogStreamOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteLogStreamOutput) GoString() string { return s.String() } type DeleteMetricFilterInput struct { _ struct{} `type:"structure"` // The name of the metric filter to delete. FilterName *string `locationName:"filterName" min:"1" type:"string" required:"true"` // The name of the log group that is associated with the metric filter to delete. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s DeleteMetricFilterInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteMetricFilterInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DeleteMetricFilterInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DeleteMetricFilterInput"} if s.FilterName == nil { invalidParams.Add(request.NewErrParamRequired("FilterName")) } if s.FilterName != nil && len(*s.FilterName) < 1 { invalidParams.Add(request.NewErrParamMinLen("FilterName", 1)) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DeleteMetricFilterOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s DeleteMetricFilterOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteMetricFilterOutput) GoString() string { return s.String() } type DeleteRetentionPolicyInput struct { _ struct{} `type:"structure"` // The name of the log group that is associated with the retention policy to // delete. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s DeleteRetentionPolicyInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteRetentionPolicyInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DeleteRetentionPolicyInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DeleteRetentionPolicyInput"} if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DeleteRetentionPolicyOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s DeleteRetentionPolicyOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteRetentionPolicyOutput) GoString() string { return s.String() } type DeleteSubscriptionFilterInput struct { _ struct{} `type:"structure"` // The name of the subscription filter to delete. FilterName *string `locationName:"filterName" min:"1" type:"string" required:"true"` // The name of the log group that is associated with the subscription filter // to delete. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s DeleteSubscriptionFilterInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteSubscriptionFilterInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DeleteSubscriptionFilterInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DeleteSubscriptionFilterInput"} if s.FilterName == nil { invalidParams.Add(request.NewErrParamRequired("FilterName")) } if s.FilterName != nil && len(*s.FilterName) < 1 { invalidParams.Add(request.NewErrParamMinLen("FilterName", 1)) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DeleteSubscriptionFilterOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s DeleteSubscriptionFilterOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DeleteSubscriptionFilterOutput) GoString() string { return s.String() } type DescribeDestinationsInput struct { _ struct{} `type:"structure"` // Will only return destinations that match the provided destinationNamePrefix. // If you don't specify a value, no prefix is applied. DestinationNamePrefix *string `min:"1" type:"string"` // The maximum number of results to return. Limit *int64 `locationName:"limit" min:"1" type:"integer"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeDestinationsInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeDestinationsInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DescribeDestinationsInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DescribeDestinationsInput"} if s.DestinationNamePrefix != nil && len(*s.DestinationNamePrefix) < 1 { invalidParams.Add(request.NewErrParamMinLen("DestinationNamePrefix", 1)) } if s.Limit != nil && *s.Limit < 1 { invalidParams.Add(request.NewErrParamMinValue("Limit", 1)) } if s.NextToken != nil && len(*s.NextToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("NextToken", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DescribeDestinationsOutput struct { _ struct{} `type:"structure"` Destinations []*Destination `locationName:"destinations" type:"list"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeDestinationsOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeDestinationsOutput) GoString() string { return s.String() } type DescribeExportTasksInput struct { _ struct{} `type:"structure"` // The maximum number of items returned in the response. If you don't specify // a value, the request would return up to 50 items. Limit *int64 `locationName:"limit" min:"1" type:"integer"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous DescribeExportTasks // request. NextToken *string `locationName:"nextToken" min:"1" type:"string"` // All export tasks that matches the specified status code will be returned. // This can return zero or more export tasks. StatusCode *string `locationName:"statusCode" type:"string" enum:"ExportTaskStatusCode"` // Export task that matches the specified task Id will be returned. This can // result in zero or one export task. TaskId *string `locationName:"taskId" min:"1" type:"string"` } // String returns the string representation func (s DescribeExportTasksInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeExportTasksInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DescribeExportTasksInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DescribeExportTasksInput"} if s.Limit != nil && *s.Limit < 1 { invalidParams.Add(request.NewErrParamMinValue("Limit", 1)) } if s.NextToken != nil && len(*s.NextToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("NextToken", 1)) } if s.TaskId != nil && len(*s.TaskId) < 1 { invalidParams.Add(request.NewErrParamMinLen("TaskId", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DescribeExportTasksOutput struct { _ struct{} `type:"structure"` // A list of export tasks. ExportTasks []*ExportTask `locationName:"exportTasks" type:"list"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeExportTasksOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeExportTasksOutput) GoString() string { return s.String() } type DescribeLogGroupsInput struct { _ struct{} `type:"structure"` // The maximum number of items returned in the response. If you don't specify // a value, the request would return up to 50 items. Limit *int64 `locationName:"limit" min:"1" type:"integer"` // Will only return log groups that match the provided logGroupNamePrefix. If // you don't specify a value, no prefix filter is applied. LogGroupNamePrefix *string `locationName:"logGroupNamePrefix" min:"1" type:"string"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous DescribeLogGroups // request. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeLogGroupsInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeLogGroupsInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DescribeLogGroupsInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DescribeLogGroupsInput"} if s.Limit != nil && *s.Limit < 1 { invalidParams.Add(request.NewErrParamMinValue("Limit", 1)) } if s.LogGroupNamePrefix != nil && len(*s.LogGroupNamePrefix) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupNamePrefix", 1)) } if s.NextToken != nil && len(*s.NextToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("NextToken", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DescribeLogGroupsOutput struct { _ struct{} `type:"structure"` // A list of log groups. LogGroups []*LogGroup `locationName:"logGroups" type:"list"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeLogGroupsOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeLogGroupsOutput) GoString() string { return s.String() } type DescribeLogStreamsInput struct { _ struct{} `type:"structure"` // If set to true, results are returned in descending order. If you don't specify // a value or set it to false, results are returned in ascending order. Descending *bool `locationName:"descending" type:"boolean"` // The maximum number of items returned in the response. If you don't specify // a value, the request would return up to 50 items. Limit *int64 `locationName:"limit" min:"1" type:"integer"` // The log group name for which log streams are to be listed. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // Will only return log streams that match the provided logStreamNamePrefix. // If you don't specify a value, no prefix filter is applied. LogStreamNamePrefix *string `locationName:"logStreamNamePrefix" min:"1" type:"string"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous DescribeLogStreams // request. NextToken *string `locationName:"nextToken" min:"1" type:"string"` // Specifies what to order the returned log streams by. Valid arguments are // 'LogStreamName' or 'LastEventTime'. If you don't specify a value, results // are ordered by LogStreamName. If 'LastEventTime' is chosen, the request cannot // also contain a logStreamNamePrefix. OrderBy *string `locationName:"orderBy" type:"string" enum:"OrderBy"` } // String returns the string representation func (s DescribeLogStreamsInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeLogStreamsInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DescribeLogStreamsInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DescribeLogStreamsInput"} if s.Limit != nil && *s.Limit < 1 { invalidParams.Add(request.NewErrParamMinValue("Limit", 1)) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.LogStreamNamePrefix != nil && len(*s.LogStreamNamePrefix) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogStreamNamePrefix", 1)) } if s.NextToken != nil && len(*s.NextToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("NextToken", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DescribeLogStreamsOutput struct { _ struct{} `type:"structure"` // A list of log streams. LogStreams []*LogStream `locationName:"logStreams" type:"list"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeLogStreamsOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeLogStreamsOutput) GoString() string { return s.String() } type DescribeMetricFiltersInput struct { _ struct{} `type:"structure"` // Will only return metric filters that match the provided filterNamePrefix. // If you don't specify a value, no prefix filter is applied. FilterNamePrefix *string `locationName:"filterNamePrefix" min:"1" type:"string"` // The maximum number of items returned in the response. If you don't specify // a value, the request would return up to 50 items. Limit *int64 `locationName:"limit" min:"1" type:"integer"` // The log group name for which metric filters are to be listed. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous DescribeMetricFilters // request. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeMetricFiltersInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeMetricFiltersInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DescribeMetricFiltersInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DescribeMetricFiltersInput"} if s.FilterNamePrefix != nil && len(*s.FilterNamePrefix) < 1 { invalidParams.Add(request.NewErrParamMinLen("FilterNamePrefix", 1)) } if s.Limit != nil && *s.Limit < 1 { invalidParams.Add(request.NewErrParamMinValue("Limit", 1)) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.NextToken != nil && len(*s.NextToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("NextToken", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DescribeMetricFiltersOutput struct { _ struct{} `type:"structure"` MetricFilters []*MetricFilter `locationName:"metricFilters" type:"list"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeMetricFiltersOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeMetricFiltersOutput) GoString() string { return s.String() } type DescribeSubscriptionFiltersInput struct { _ struct{} `type:"structure"` // Will only return subscription filters that match the provided filterNamePrefix. // If you don't specify a value, no prefix filter is applied. FilterNamePrefix *string `locationName:"filterNamePrefix" min:"1" type:"string"` // The maximum number of results to return. Limit *int64 `locationName:"limit" min:"1" type:"integer"` // The log group name for which subscription filters are to be listed. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextToken *string `locationName:"nextToken" min:"1" type:"string"` } // String returns the string representation func (s DescribeSubscriptionFiltersInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeSubscriptionFiltersInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DescribeSubscriptionFiltersInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DescribeSubscriptionFiltersInput"} if s.FilterNamePrefix != nil && len(*s.FilterNamePrefix) < 1 { invalidParams.Add(request.NewErrParamMinLen("FilterNamePrefix", 1)) } if s.Limit != nil && *s.Limit < 1 { invalidParams.Add(request.NewErrParamMinValue("Limit", 1)) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.NextToken != nil && len(*s.NextToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("NextToken", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type DescribeSubscriptionFiltersOutput struct { _ struct{} `type:"structure"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextToken *string `locationName:"nextToken" min:"1" type:"string"` SubscriptionFilters []*SubscriptionFilter `locationName:"subscriptionFilters" type:"list"` } // String returns the string representation func (s DescribeSubscriptionFiltersOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DescribeSubscriptionFiltersOutput) GoString() string { return s.String() } // A cross account destination that is the recipient of subscription log events. type Destination struct { _ struct{} `type:"structure"` // An IAM policy document that governs which AWS accounts can create subscription // filters against this destination. AccessPolicy *string `locationName:"accessPolicy" min:"1" type:"string"` // ARN of this destination. Arn *string `locationName:"arn" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC specifying when this destination was created. CreationTime *int64 `locationName:"creationTime" type:"long"` // Name of the destination. DestinationName *string `locationName:"destinationName" min:"1" type:"string"` // A role for impersonation for delivering log events to the target. RoleArn *string `locationName:"roleArn" min:"1" type:"string"` // ARN of the physical target where the log events will be delivered (eg. ARN // of a Kinesis stream). TargetArn *string `locationName:"targetArn" min:"1" type:"string"` } // String returns the string representation func (s Destination) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s Destination) GoString() string { return s.String() } // Represents an export task. type ExportTask struct { _ struct{} `type:"structure"` // Name of Amazon S3 bucket to which the log data was exported. Destination *string `locationName:"destination" min:"1" type:"string"` // Prefix that was used as the start of Amazon S3 key for every object exported. DestinationPrefix *string `locationName:"destinationPrefix" type:"string"` // Execution info about the export task. ExecutionInfo *ExportTaskExecutionInfo `locationName:"executionInfo" type:"structure"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. Events with a timestamp prior to this time are not exported. From *int64 `locationName:"from" type:"long"` // The name of the log group from which logs data was exported. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string"` // Status of the export task. Status *ExportTaskStatus `locationName:"status" type:"structure"` // Id of the export task. TaskId *string `locationName:"taskId" min:"1" type:"string"` // The name of the export task. TaskName *string `locationName:"taskName" min:"1" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. Events with a timestamp later than this time are not exported. To *int64 `locationName:"to" type:"long"` } // String returns the string representation func (s ExportTask) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s ExportTask) GoString() string { return s.String() } // Represents the status of an export task. type ExportTaskExecutionInfo struct { _ struct{} `type:"structure"` // A point in time when the export task got completed. CompletionTime *int64 `locationName:"completionTime" type:"long"` // A point in time when the export task got created. CreationTime *int64 `locationName:"creationTime" type:"long"` } // String returns the string representation func (s ExportTaskExecutionInfo) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s ExportTaskExecutionInfo) GoString() string { return s.String() } // Represents the status of an export task. type ExportTaskStatus struct { _ struct{} `type:"structure"` // Status code of the export task. Code *string `locationName:"code" type:"string" enum:"ExportTaskStatusCode"` // Status message related to the code. Message *string `locationName:"message" type:"string"` } // String returns the string representation func (s ExportTaskStatus) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s ExportTaskStatus) GoString() string { return s.String() } type FilterLogEventsInput struct { _ struct{} `type:"structure"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. If provided, events with a timestamp later than this time are // not returned. EndTime *int64 `locationName:"endTime" type:"long"` // A valid CloudWatch Logs filter pattern to use for filtering the response. // If not provided, all the events are matched. FilterPattern *string `locationName:"filterPattern" type:"string"` // If provided, the API will make a best effort to provide responses that contain // events from multiple log streams within the log group interleaved in a single // response. If not provided, all the matched log events in the first log stream // will be searched first, then those in the next log stream, etc. Interleaved *bool `locationName:"interleaved" type:"boolean"` // The maximum number of events to return in a page of results. Default is 10,000 // events. Limit *int64 `locationName:"limit" min:"1" type:"integer"` // The name of the log group to query. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // Optional list of log stream names within the specified log group to search. // Defaults to all the log streams in the log group. LogStreamNames []*string `locationName:"logStreamNames" min:"1" type:"list"` // A pagination token obtained from a FilterLogEvents response to continue paginating // the FilterLogEvents results. This token is omitted from the response when // there are no other events to display. NextToken *string `locationName:"nextToken" min:"1" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. If provided, events with a timestamp prior to this time are // not returned. StartTime *int64 `locationName:"startTime" type:"long"` } // String returns the string representation func (s FilterLogEventsInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s FilterLogEventsInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *FilterLogEventsInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "FilterLogEventsInput"} if s.Limit != nil && *s.Limit < 1 { invalidParams.Add(request.NewErrParamMinValue("Limit", 1)) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.LogStreamNames != nil && len(s.LogStreamNames) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogStreamNames", 1)) } if s.NextToken != nil && len(*s.NextToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("NextToken", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type FilterLogEventsOutput struct { _ struct{} `type:"structure"` // A list of FilteredLogEvent objects representing the matched events from the // request. Events []*FilteredLogEvent `locationName:"events" type:"list"` // A pagination token obtained from a FilterLogEvents response to continue paginating // the FilterLogEvents results. This token is omitted from the response when // there are no other events to display. NextToken *string `locationName:"nextToken" min:"1" type:"string"` // A list of SearchedLogStream objects indicating which log streams have been // searched in this request and whether each has been searched completely or // still has more to be paginated. SearchedLogStreams []*SearchedLogStream `locationName:"searchedLogStreams" type:"list"` } // String returns the string representation func (s FilterLogEventsOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s FilterLogEventsOutput) GoString() string { return s.String() } // Represents a matched event from a FilterLogEvents request. type FilteredLogEvent struct { _ struct{} `type:"structure"` // A unique identifier for this event. EventId *string `locationName:"eventId" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. IngestionTime *int64 `locationName:"ingestionTime" type:"long"` // The name of the log stream this event belongs to. LogStreamName *string `locationName:"logStreamName" min:"1" type:"string"` // The data contained in the log event. Message *string `locationName:"message" min:"1" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. Timestamp *int64 `locationName:"timestamp" type:"long"` } // String returns the string representation func (s FilteredLogEvent) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s FilteredLogEvent) GoString() string { return s.String() } type GetLogEventsInput struct { _ struct{} `type:"structure"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. EndTime *int64 `locationName:"endTime" type:"long"` // The maximum number of log events returned in the response. If you don't specify // a value, the request would return as many log events as can fit in a response // size of 1MB, up to 10,000 log events. Limit *int64 `locationName:"limit" min:"1" type:"integer"` // The name of the log group to query. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // The name of the log stream to query. LogStreamName *string `locationName:"logStreamName" min:"1" type:"string" required:"true"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the nextForwardToken or nextBackwardToken // fields in the response of the previous GetLogEvents request. NextToken *string `locationName:"nextToken" min:"1" type:"string"` // If set to true, the earliest log events would be returned first. The default // is false (the latest log events are returned first). StartFromHead *bool `locationName:"startFromHead" type:"boolean"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. StartTime *int64 `locationName:"startTime" type:"long"` } // String returns the string representation func (s GetLogEventsInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s GetLogEventsInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *GetLogEventsInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "GetLogEventsInput"} if s.Limit != nil && *s.Limit < 1 { invalidParams.Add(request.NewErrParamMinValue("Limit", 1)) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.LogStreamName == nil { invalidParams.Add(request.NewErrParamRequired("LogStreamName")) } if s.LogStreamName != nil && len(*s.LogStreamName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogStreamName", 1)) } if s.NextToken != nil && len(*s.NextToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("NextToken", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type GetLogEventsOutput struct { _ struct{} `type:"structure"` Events []*OutputLogEvent `locationName:"events" type:"list"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextBackwardToken *string `locationName:"nextBackwardToken" min:"1" type:"string"` // A string token used for pagination that points to the next page of results. // It must be a value obtained from the response of the previous request. The // token expires after 24 hours. NextForwardToken *string `locationName:"nextForwardToken" min:"1" type:"string"` } // String returns the string representation func (s GetLogEventsOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s GetLogEventsOutput) GoString() string { return s.String() } // A log event is a record of some activity that was recorded by the application // or resource being monitored. The log event record that CloudWatch Logs understands // contains two properties: the timestamp of when the event occurred, and the // raw event message. type InputLogEvent struct { _ struct{} `type:"structure"` Message *string `locationName:"message" min:"1" type:"string" required:"true"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. Timestamp *int64 `locationName:"timestamp" type:"long" required:"true"` } // String returns the string representation func (s InputLogEvent) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s InputLogEvent) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *InputLogEvent) Validate() error { invalidParams := request.ErrInvalidParams{Context: "InputLogEvent"} if s.Message == nil { invalidParams.Add(request.NewErrParamRequired("Message")) } if s.Message != nil && len(*s.Message) < 1 { invalidParams.Add(request.NewErrParamMinLen("Message", 1)) } if s.Timestamp == nil { invalidParams.Add(request.NewErrParamRequired("Timestamp")) } if invalidParams.Len() > 0 { return invalidParams } return nil } type LogGroup struct { _ struct{} `type:"structure"` Arn *string `locationName:"arn" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. CreationTime *int64 `locationName:"creationTime" type:"long"` LogGroupName *string `locationName:"logGroupName" min:"1" type:"string"` // The number of metric filters associated with the log group. MetricFilterCount *int64 `locationName:"metricFilterCount" type:"integer"` // Specifies the number of days you want to retain log events in the specified // log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, // 365, 400, 545, 731, 1827, 3653. RetentionInDays *int64 `locationName:"retentionInDays" type:"integer"` StoredBytes *int64 `locationName:"storedBytes" type:"long"` } // String returns the string representation func (s LogGroup) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s LogGroup) GoString() string { return s.String() } // A log stream is sequence of log events from a single emitter of logs. type LogStream struct { _ struct{} `type:"structure"` Arn *string `locationName:"arn" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. CreationTime *int64 `locationName:"creationTime" type:"long"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. FirstEventTimestamp *int64 `locationName:"firstEventTimestamp" type:"long"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. LastEventTimestamp *int64 `locationName:"lastEventTimestamp" type:"long"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. LastIngestionTime *int64 `locationName:"lastIngestionTime" type:"long"` LogStreamName *string `locationName:"logStreamName" min:"1" type:"string"` StoredBytes *int64 `locationName:"storedBytes" type:"long"` // A string token used for making PutLogEvents requests. A sequenceToken can // only be used once, and PutLogEvents requests must include the sequenceToken // obtained from the response of the previous request. UploadSequenceToken *string `locationName:"uploadSequenceToken" min:"1" type:"string"` } // String returns the string representation func (s LogStream) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s LogStream) GoString() string { return s.String() } // Metric filters can be used to express how CloudWatch Logs would extract metric // observations from ingested log events and transform them to metric data in // a CloudWatch metric. type MetricFilter struct { _ struct{} `type:"structure"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. CreationTime *int64 `locationName:"creationTime" type:"long"` // A name for a metric or subscription filter. FilterName *string `locationName:"filterName" min:"1" type:"string"` // A symbolic description of how CloudWatch Logs should interpret the data in // each log event. For example, a log event may contain timestamps, IP addresses, // strings, and so on. You use the filter pattern to specify what to look for // in the log event message. FilterPattern *string `locationName:"filterPattern" type:"string"` MetricTransformations []*MetricTransformation `locationName:"metricTransformations" min:"1" type:"list"` } // String returns the string representation func (s MetricFilter) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s MetricFilter) GoString() string { return s.String() } type MetricFilterMatchRecord struct { _ struct{} `type:"structure"` EventMessage *string `locationName:"eventMessage" min:"1" type:"string"` EventNumber *int64 `locationName:"eventNumber" type:"long"` ExtractedValues map[string]*string `locationName:"extractedValues" type:"map"` } // String returns the string representation func (s MetricFilterMatchRecord) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s MetricFilterMatchRecord) GoString() string { return s.String() } type MetricTransformation struct { _ struct{} `type:"structure"` // (Optional) A default value to emit when a filter pattern does not match a // log event. Can be null. DefaultValue *float64 `locationName:"defaultValue" type:"double"` // Name of the metric. MetricName *string `locationName:"metricName" type:"string" required:"true"` // Namespace to which the metric belongs. MetricNamespace *string `locationName:"metricNamespace" type:"string" required:"true"` // A string representing a value to publish to this metric when a filter pattern // matches a log event. MetricValue *string `locationName:"metricValue" type:"string" required:"true"` } // String returns the string representation func (s MetricTransformation) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s MetricTransformation) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *MetricTransformation) Validate() error { invalidParams := request.ErrInvalidParams{Context: "MetricTransformation"} if s.MetricName == nil { invalidParams.Add(request.NewErrParamRequired("MetricName")) } if s.MetricNamespace == nil { invalidParams.Add(request.NewErrParamRequired("MetricNamespace")) } if s.MetricValue == nil { invalidParams.Add(request.NewErrParamRequired("MetricValue")) } if invalidParams.Len() > 0 { return invalidParams } return nil } type OutputLogEvent struct { _ struct{} `type:"structure"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. IngestionTime *int64 `locationName:"ingestionTime" type:"long"` Message *string `locationName:"message" min:"1" type:"string"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. Timestamp *int64 `locationName:"timestamp" type:"long"` } // String returns the string representation func (s OutputLogEvent) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s OutputLogEvent) GoString() string { return s.String() } type PutDestinationInput struct { _ struct{} `type:"structure"` // A name for the destination. DestinationName *string `locationName:"destinationName" min:"1" type:"string" required:"true"` // The ARN of an IAM role that grants CloudWatch Logs permissions to do Amazon // Kinesis PutRecord requests on the destination stream. RoleArn *string `locationName:"roleArn" min:"1" type:"string" required:"true"` // The ARN of an Amazon Kinesis stream to deliver matching log events to. TargetArn *string `locationName:"targetArn" min:"1" type:"string" required:"true"` } // String returns the string representation func (s PutDestinationInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutDestinationInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *PutDestinationInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "PutDestinationInput"} if s.DestinationName == nil { invalidParams.Add(request.NewErrParamRequired("DestinationName")) } if s.DestinationName != nil && len(*s.DestinationName) < 1 { invalidParams.Add(request.NewErrParamMinLen("DestinationName", 1)) } if s.RoleArn == nil { invalidParams.Add(request.NewErrParamRequired("RoleArn")) } if s.RoleArn != nil && len(*s.RoleArn) < 1 { invalidParams.Add(request.NewErrParamMinLen("RoleArn", 1)) } if s.TargetArn == nil { invalidParams.Add(request.NewErrParamRequired("TargetArn")) } if s.TargetArn != nil && len(*s.TargetArn) < 1 { invalidParams.Add(request.NewErrParamMinLen("TargetArn", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type PutDestinationOutput struct { _ struct{} `type:"structure"` // A cross account destination that is the recipient of subscription log events. Destination *Destination `locationName:"destination" type:"structure"` } // String returns the string representation func (s PutDestinationOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutDestinationOutput) GoString() string { return s.String() } type PutDestinationPolicyInput struct { _ struct{} `type:"structure"` // An IAM policy document that authorizes cross-account users to deliver their // log events to associated destination. AccessPolicy *string `locationName:"accessPolicy" min:"1" type:"string" required:"true"` // A name for an existing destination. DestinationName *string `locationName:"destinationName" min:"1" type:"string" required:"true"` } // String returns the string representation func (s PutDestinationPolicyInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutDestinationPolicyInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *PutDestinationPolicyInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "PutDestinationPolicyInput"} if s.AccessPolicy == nil { invalidParams.Add(request.NewErrParamRequired("AccessPolicy")) } if s.AccessPolicy != nil && len(*s.AccessPolicy) < 1 { invalidParams.Add(request.NewErrParamMinLen("AccessPolicy", 1)) } if s.DestinationName == nil { invalidParams.Add(request.NewErrParamRequired("DestinationName")) } if s.DestinationName != nil && len(*s.DestinationName) < 1 { invalidParams.Add(request.NewErrParamMinLen("DestinationName", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type PutDestinationPolicyOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s PutDestinationPolicyOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutDestinationPolicyOutput) GoString() string { return s.String() } type PutLogEventsInput struct { _ struct{} `type:"structure"` // A list of log events belonging to a log stream. LogEvents []*InputLogEvent `locationName:"logEvents" min:"1" type:"list" required:"true"` // The name of the log group to put log events to. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // The name of the log stream to put log events to. LogStreamName *string `locationName:"logStreamName" min:"1" type:"string" required:"true"` // A string token that must be obtained from the response of the previous PutLogEvents // request. SequenceToken *string `locationName:"sequenceToken" min:"1" type:"string"` } // String returns the string representation func (s PutLogEventsInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutLogEventsInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *PutLogEventsInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "PutLogEventsInput"} if s.LogEvents == nil { invalidParams.Add(request.NewErrParamRequired("LogEvents")) } if s.LogEvents != nil && len(s.LogEvents) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogEvents", 1)) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.LogStreamName == nil { invalidParams.Add(request.NewErrParamRequired("LogStreamName")) } if s.LogStreamName != nil && len(*s.LogStreamName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogStreamName", 1)) } if s.SequenceToken != nil && len(*s.SequenceToken) < 1 { invalidParams.Add(request.NewErrParamMinLen("SequenceToken", 1)) } if s.LogEvents != nil { for i, v := range s.LogEvents { if v == nil { continue } if err := v.Validate(); err != nil { invalidParams.AddNested(fmt.Sprintf("%s[%v]", "LogEvents", i), err.(request.ErrInvalidParams)) } } } if invalidParams.Len() > 0 { return invalidParams } return nil } type PutLogEventsOutput struct { _ struct{} `type:"structure"` // A string token used for making PutLogEvents requests. A sequenceToken can // only be used once, and PutLogEvents requests must include the sequenceToken // obtained from the response of the previous request. NextSequenceToken *string `locationName:"nextSequenceToken" min:"1" type:"string"` RejectedLogEventsInfo *RejectedLogEventsInfo `locationName:"rejectedLogEventsInfo" type:"structure"` } // String returns the string representation func (s PutLogEventsOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutLogEventsOutput) GoString() string { return s.String() } type PutMetricFilterInput struct { _ struct{} `type:"structure"` // A name for the metric filter. FilterName *string `locationName:"filterName" min:"1" type:"string" required:"true"` // A valid CloudWatch Logs filter pattern for extracting metric data out of // ingested log events. FilterPattern *string `locationName:"filterPattern" type:"string" required:"true"` // The name of the log group to associate the metric filter with. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // A collection of information needed to define how metric data gets emitted. MetricTransformations []*MetricTransformation `locationName:"metricTransformations" min:"1" type:"list" required:"true"` } // String returns the string representation func (s PutMetricFilterInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutMetricFilterInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *PutMetricFilterInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "PutMetricFilterInput"} if s.FilterName == nil { invalidParams.Add(request.NewErrParamRequired("FilterName")) } if s.FilterName != nil && len(*s.FilterName) < 1 { invalidParams.Add(request.NewErrParamMinLen("FilterName", 1)) } if s.FilterPattern == nil { invalidParams.Add(request.NewErrParamRequired("FilterPattern")) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.MetricTransformations == nil { invalidParams.Add(request.NewErrParamRequired("MetricTransformations")) } if s.MetricTransformations != nil && len(s.MetricTransformations) < 1 { invalidParams.Add(request.NewErrParamMinLen("MetricTransformations", 1)) } if s.MetricTransformations != nil { for i, v := range s.MetricTransformations { if v == nil { continue } if err := v.Validate(); err != nil { invalidParams.AddNested(fmt.Sprintf("%s[%v]", "MetricTransformations", i), err.(request.ErrInvalidParams)) } } } if invalidParams.Len() > 0 { return invalidParams } return nil } type PutMetricFilterOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s PutMetricFilterOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutMetricFilterOutput) GoString() string { return s.String() } type PutRetentionPolicyInput struct { _ struct{} `type:"structure"` // The name of the log group to associate the retention policy with. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // Specifies the number of days you want to retain log events in the specified // log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, // 365, 400, 545, 731, 1827, 3653. RetentionInDays *int64 `locationName:"retentionInDays" type:"integer" required:"true"` } // String returns the string representation func (s PutRetentionPolicyInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutRetentionPolicyInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *PutRetentionPolicyInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "PutRetentionPolicyInput"} if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.RetentionInDays == nil { invalidParams.Add(request.NewErrParamRequired("RetentionInDays")) } if invalidParams.Len() > 0 { return invalidParams } return nil } type PutRetentionPolicyOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s PutRetentionPolicyOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutRetentionPolicyOutput) GoString() string { return s.String() } type PutSubscriptionFilterInput struct { _ struct{} `type:"structure"` // The ARN of the destination to deliver matching log events to. Currently, // the supported destinations are: // // An Amazon Kinesis stream belonging to the same account as the subscription // filter, for same-account delivery. // // A logical destination (used via an ARN of Destination) belonging to a // different account, for cross-account delivery. // // An Amazon Kinesis Firehose stream belonging to the same account as the // subscription filter, for same-account delivery. // // An AWS Lambda function belonging to the same account as the subscription // filter, for same-account delivery. DestinationArn *string `locationName:"destinationArn" min:"1" type:"string" required:"true"` // A name for the subscription filter. FilterName *string `locationName:"filterName" min:"1" type:"string" required:"true"` // A valid CloudWatch Logs filter pattern for subscribing to a filtered stream // of log events. FilterPattern *string `locationName:"filterPattern" type:"string" required:"true"` // The name of the log group to associate the subscription filter with. LogGroupName *string `locationName:"logGroupName" min:"1" type:"string" required:"true"` // The ARN of an IAM role that grants CloudWatch Logs permissions to deliver // ingested log events to the destination stream. You don't need to provide // the ARN when you are working with a logical destination (used via an ARN // of Destination) for cross-account delivery. RoleArn *string `locationName:"roleArn" min:"1" type:"string"` } // String returns the string representation func (s PutSubscriptionFilterInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutSubscriptionFilterInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *PutSubscriptionFilterInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "PutSubscriptionFilterInput"} if s.DestinationArn == nil { invalidParams.Add(request.NewErrParamRequired("DestinationArn")) } if s.DestinationArn != nil && len(*s.DestinationArn) < 1 { invalidParams.Add(request.NewErrParamMinLen("DestinationArn", 1)) } if s.FilterName == nil { invalidParams.Add(request.NewErrParamRequired("FilterName")) } if s.FilterName != nil && len(*s.FilterName) < 1 { invalidParams.Add(request.NewErrParamMinLen("FilterName", 1)) } if s.FilterPattern == nil { invalidParams.Add(request.NewErrParamRequired("FilterPattern")) } if s.LogGroupName == nil { invalidParams.Add(request.NewErrParamRequired("LogGroupName")) } if s.LogGroupName != nil && len(*s.LogGroupName) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogGroupName", 1)) } if s.RoleArn != nil && len(*s.RoleArn) < 1 { invalidParams.Add(request.NewErrParamMinLen("RoleArn", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type PutSubscriptionFilterOutput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s PutSubscriptionFilterOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s PutSubscriptionFilterOutput) GoString() string { return s.String() } type RejectedLogEventsInfo struct { _ struct{} `type:"structure"` ExpiredLogEventEndIndex *int64 `locationName:"expiredLogEventEndIndex" type:"integer"` TooNewLogEventStartIndex *int64 `locationName:"tooNewLogEventStartIndex" type:"integer"` TooOldLogEventEndIndex *int64 `locationName:"tooOldLogEventEndIndex" type:"integer"` } // String returns the string representation func (s RejectedLogEventsInfo) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s RejectedLogEventsInfo) GoString() string { return s.String() } // An object indicating the search status of a log stream in a FilterLogEvents // request. type SearchedLogStream struct { _ struct{} `type:"structure"` // The name of the log stream. LogStreamName *string `locationName:"logStreamName" min:"1" type:"string"` // Indicates whether all the events in this log stream were searched or more // data exists to search by paginating further. SearchedCompletely *bool `locationName:"searchedCompletely" type:"boolean"` } // String returns the string representation func (s SearchedLogStream) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s SearchedLogStream) GoString() string { return s.String() } type SubscriptionFilter struct { _ struct{} `type:"structure"` // A point in time expressed as the number of milliseconds since Jan 1, 1970 // 00:00:00 UTC. CreationTime *int64 `locationName:"creationTime" type:"long"` DestinationArn *string `locationName:"destinationArn" min:"1" type:"string"` // A name for a metric or subscription filter. FilterName *string `locationName:"filterName" min:"1" type:"string"` // A symbolic description of how CloudWatch Logs should interpret the data in // each log event. For example, a log event may contain timestamps, IP addresses, // strings, and so on. You use the filter pattern to specify what to look for // in the log event message. FilterPattern *string `locationName:"filterPattern" type:"string"` LogGroupName *string `locationName:"logGroupName" min:"1" type:"string"` RoleArn *string `locationName:"roleArn" min:"1" type:"string"` } // String returns the string representation func (s SubscriptionFilter) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s SubscriptionFilter) GoString() string { return s.String() } type TestMetricFilterInput struct { _ struct{} `type:"structure"` // A symbolic description of how CloudWatch Logs should interpret the data in // each log event. For example, a log event may contain timestamps, IP addresses, // strings, and so on. You use the filter pattern to specify what to look for // in the log event message. FilterPattern *string `locationName:"filterPattern" type:"string" required:"true"` // A list of log event messages to test. LogEventMessages []*string `locationName:"logEventMessages" min:"1" type:"list" required:"true"` } // String returns the string representation func (s TestMetricFilterInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s TestMetricFilterInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *TestMetricFilterInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "TestMetricFilterInput"} if s.FilterPattern == nil { invalidParams.Add(request.NewErrParamRequired("FilterPattern")) } if s.LogEventMessages == nil { invalidParams.Add(request.NewErrParamRequired("LogEventMessages")) } if s.LogEventMessages != nil && len(s.LogEventMessages) < 1 { invalidParams.Add(request.NewErrParamMinLen("LogEventMessages", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } type TestMetricFilterOutput struct { _ struct{} `type:"structure"` Matches []*MetricFilterMatchRecord `locationName:"matches" type:"list"` } // String returns the string representation func (s TestMetricFilterOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s TestMetricFilterOutput) GoString() string { return s.String() } const ( // @enum ExportTaskStatusCode ExportTaskStatusCodeCancelled = "CANCELLED" // @enum ExportTaskStatusCode ExportTaskStatusCodeCompleted = "COMPLETED" // @enum ExportTaskStatusCode ExportTaskStatusCodeFailed = "FAILED" // @enum ExportTaskStatusCode ExportTaskStatusCodePending = "PENDING" // @enum ExportTaskStatusCode ExportTaskStatusCodePendingCancel = "PENDING_CANCEL" // @enum ExportTaskStatusCode ExportTaskStatusCodeRunning = "RUNNING" ) const ( // @enum OrderBy OrderByLogStreamName = "LogStreamName" // @enum OrderBy OrderByLastEventTime = "LastEventTime" ) ================================================ FILE: vendor/github.com/aws/aws-sdk-go/service/cloudwatchlogs/service.go ================================================ // THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. package cloudwatchlogs import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/client/metadata" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/signer/v4" "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" ) // You can use Amazon CloudWatch Logs to monitor, store, and access your log // files from Amazon Elastic Compute Cloud (Amazon EC2) instances, Amazon CloudTrail, // or other sources. You can then retrieve the associated log data from CloudWatch // Logs using the Amazon CloudWatch console, the CloudWatch Logs commands in // the AWS CLI, the CloudWatch Logs API, or the CloudWatch Logs SDK. // // You can use CloudWatch Logs to: // // Monitor Logs from Amazon EC2 Instances in Real-time: You can use CloudWatch // Logs to monitor applications and systems using log data. For example, CloudWatch // Logs can track the number of errors that occur in your application logs and // send you a notification whenever the rate of errors exceeds a threshold you // specify. CloudWatch Logs uses your log data for monitoring; so, no code changes // are required. For example, you can monitor application logs for specific // literal terms (such as "NullReferenceException") or count the number of occurrences // of a literal term at a particular position in log data (such as "404" status // codes in an Apache access log). When the term you are searching for is found, // CloudWatch Logs reports the data to a Amazon CloudWatch metric that you specify. // // Monitor Amazon CloudTrail Logged Events: You can create alarms in Amazon // CloudWatch and receive notifications of particular API activity as captured // by CloudTrail and use the notification to perform troubleshooting. // // Archive Log Data: You can use CloudWatch Logs to store your log data // in highly durable storage. You can change the log retention setting so that // any log events older than this setting are automatically deleted. The CloudWatch // Logs agent makes it easy to quickly send both rotated and non-rotated log // data off of a host and into the log service. You can then access the raw // log data when you need it. //The service client's operations are safe to be used concurrently. // It is not safe to mutate any of the client's properties though. type CloudWatchLogs struct { *client.Client } // Used for custom client initialization logic var initClient func(*client.Client) // Used for custom request initialization logic var initRequest func(*request.Request) // A ServiceName is the name of the service the client will make API calls to. const ServiceName = "logs" // New creates a new instance of the CloudWatchLogs client with a session. // If additional configuration is needed for the client instance use the optional // aws.Config parameter to add your extra config. // // Example: // // Create a CloudWatchLogs client from just a session. // svc := cloudwatchlogs.New(mySession) // // // Create a CloudWatchLogs client with additional configuration // svc := cloudwatchlogs.New(mySession, aws.NewConfig().WithRegion("us-west-2")) func New(p client.ConfigProvider, cfgs ...*aws.Config) *CloudWatchLogs { c := p.ClientConfig(ServiceName, cfgs...) return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion) } // newClient creates, initializes and returns a new service client instance. func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *CloudWatchLogs { svc := &CloudWatchLogs{ Client: client.New( cfg, metadata.ClientInfo{ ServiceName: ServiceName, SigningRegion: signingRegion, Endpoint: endpoint, APIVersion: "2014-03-28", JSONVersion: "1.1", TargetPrefix: "Logs_20140328", }, handlers, ), } // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler) svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler) svc.Handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler) // Run custom client initialization if present if initClient != nil { initClient(svc.Client) } return svc } // newRequest creates a new request for a CloudWatchLogs operation and runs any // custom request initialization. func (c *CloudWatchLogs) newRequest(op *request.Operation, params, data interface{}) *request.Request { req := c.NewRequest(op, params, data) // Run custom request initialization if present if initRequest != nil { initRequest(req) } return req } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/service/sts/api.go ================================================ // THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. // Package sts provides a client for AWS Security Token Service. package sts import ( "time" "github.com/aws/aws-sdk-go/aws/awsutil" "github.com/aws/aws-sdk-go/aws/request" ) const opAssumeRole = "AssumeRole" // AssumeRoleRequest generates a "aws/request.Request" representing the // client's request for the AssumeRole operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the AssumeRole method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the AssumeRoleRequest method. // req, resp := client.AssumeRoleRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, output *AssumeRoleOutput) { op := &request.Operation{ Name: opAssumeRole, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &AssumeRoleInput{} } req = c.newRequest(op, input, output) output = &AssumeRoleOutput{} req.Data = output return } // Returns a set of temporary security credentials (consisting of an access // key ID, a secret access key, and a security token) that you can use to access // AWS resources that you might not normally have access to. Typically, you // use AssumeRole for cross-account access or federation. For a comparison of // AssumeRole with the other APIs that produce temporary credentials, see Requesting // Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) // and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // Important: You cannot call AssumeRole by using AWS root account credentials; // access is denied. You must use credentials for an IAM user or an IAM role // to call AssumeRole. // // For cross-account access, imagine that you own multiple accounts and need // to access resources in each account. You could create long-term credentials // in each account to access those resources. However, managing all those credentials // and remembering which one can access which account can be time consuming. // Instead, you can create one set of long-term credentials in one account and // then use temporary security credentials to access all the other accounts // by assuming roles in those accounts. For more information about roles, see // IAM Roles (Delegation and Federation) (http://docs.aws.amazon.com/IAM/latest/UserGuide/roles-toplevel.html) // in the IAM User Guide. // // For federation, you can, for example, grant single sign-on access to the // AWS Management Console. If you already have an identity and authentication // system in your corporate network, you don't have to recreate user identities // in AWS in order to grant those user identities access to AWS. Instead, after // a user has been authenticated, you call AssumeRole (and specify the role // with the appropriate permissions) to get temporary security credentials for // that user. With those temporary security credentials, you construct a sign-in // URL that users can use to access the console. For more information, see Common // Scenarios for Temporary Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html#sts-introduction) // in the IAM User Guide. // // The temporary security credentials are valid for the duration that you specified // when calling AssumeRole, which can be from 900 seconds (15 minutes) to a // maximum of 3600 seconds (1 hour). The default is 1 hour. // // The temporary security credentials created by AssumeRole can be used to // make API calls to any AWS service with the following exception: you cannot // call the STS service's GetFederationToken or GetSessionToken APIs. // // Optionally, you can pass an IAM access policy to this operation. If you // choose not to pass a policy, the temporary security credentials that are // returned by the operation have the permissions that are defined in the access // policy of the role that is being assumed. If you pass a policy to this operation, // the temporary security credentials that are returned by the operation have // the permissions that are allowed by both the access policy of the role that // is being assumed, and the policy that you pass. This gives you a way to // further restrict the permissions for the resulting temporary security credentials. // You cannot use the passed policy to grant permissions that are in excess // of those allowed by the access policy of the role that is being assumed. // For more information, see Permissions for AssumeRole, AssumeRoleWithSAML, // and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) // in the IAM User Guide. // // To assume a role, your AWS account must be trusted by the role. The trust // relationship is defined in the role's trust policy when the role is created. // That trust policy states which accounts are allowed to delegate access to // this account's role. // // The user who wants to access the role must also have permissions delegated // from the role's administrator. If the user is in a different account than // the role, then the user's administrator must attach a policy that allows // the user to call AssumeRole on the ARN of the role in the other account. // If the user is in the same account as the role, then you can either attach // a policy to the user (identical to the previous different account user), // or you can add the user as a principal directly in the role's trust policy // // Using MFA with AssumeRole // // You can optionally include multi-factor authentication (MFA) information // when you call AssumeRole. This is useful for cross-account scenarios in which // you want to make sure that the user who is assuming the role has been authenticated // using an AWS MFA device. In that scenario, the trust policy of the role being // assumed includes a condition that tests for MFA authentication; if the caller // does not include valid MFA information, the request to assume the role is // denied. The condition in a trust policy that tests for MFA authentication // might look like the following example. // // "Condition": {"Bool": {"aws:MultiFactorAuthPresent": true}} // // For more information, see Configuring MFA-Protected API Access (http://docs.aws.amazon.com/IAM/latest/UserGuide/MFAProtectedAPI.html) // in the IAM User Guide guide. // // To use MFA with AssumeRole, you pass values for the SerialNumber and TokenCode // parameters. The SerialNumber value identifies the user's hardware or virtual // MFA device. The TokenCode is the time-based one-time password (TOTP) that // the MFA devices produces. func (c *STS) AssumeRole(input *AssumeRoleInput) (*AssumeRoleOutput, error) { req, out := c.AssumeRoleRequest(input) err := req.Send() return out, err } const opAssumeRoleWithSAML = "AssumeRoleWithSAML" // AssumeRoleWithSAMLRequest generates a "aws/request.Request" representing the // client's request for the AssumeRoleWithSAML operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the AssumeRoleWithSAML method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the AssumeRoleWithSAMLRequest method. // req, resp := client.AssumeRoleWithSAMLRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *request.Request, output *AssumeRoleWithSAMLOutput) { op := &request.Operation{ Name: opAssumeRoleWithSAML, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &AssumeRoleWithSAMLInput{} } req = c.newRequest(op, input, output) output = &AssumeRoleWithSAMLOutput{} req.Data = output return } // Returns a set of temporary security credentials for users who have been authenticated // via a SAML authentication response. This operation provides a mechanism for // tying an enterprise identity store or directory to role-based AWS access // without user-specific credentials or configuration. For a comparison of AssumeRoleWithSAML // with the other APIs that produce temporary credentials, see Requesting Temporary // Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) // and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // The temporary security credentials returned by this operation consist of // an access key ID, a secret access key, and a security token. Applications // can use these temporary security credentials to sign calls to AWS services. // // The temporary security credentials are valid for the duration that you specified // when calling AssumeRole, or until the time specified in the SAML authentication // response's SessionNotOnOrAfter value, whichever is shorter. The duration // can be from 900 seconds (15 minutes) to a maximum of 3600 seconds (1 hour). // The default is 1 hour. // // The temporary security credentials created by AssumeRoleWithSAML can be // used to make API calls to any AWS service with the following exception: you // cannot call the STS service's GetFederationToken or GetSessionToken APIs. // // Optionally, you can pass an IAM access policy to this operation. If you // choose not to pass a policy, the temporary security credentials that are // returned by the operation have the permissions that are defined in the access // policy of the role that is being assumed. If you pass a policy to this operation, // the temporary security credentials that are returned by the operation have // the permissions that are allowed by the intersection of both the access policy // of the role that is being assumed, and the policy that you pass. This means // that both policies must grant the permission for the action to be allowed. // This gives you a way to further restrict the permissions for the resulting // temporary security credentials. You cannot use the passed policy to grant // permissions that are in excess of those allowed by the access policy of the // role that is being assumed. For more information, see Permissions for AssumeRole, // AssumeRoleWithSAML, and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) // in the IAM User Guide. // // Before your application can call AssumeRoleWithSAML, you must configure // your SAML identity provider (IdP) to issue the claims required by AWS. Additionally, // you must use AWS Identity and Access Management (IAM) to create a SAML provider // entity in your AWS account that represents your identity provider, and create // an IAM role that specifies this SAML provider in its trust policy. // // Calling AssumeRoleWithSAML does not require the use of AWS security credentials. // The identity of the caller is validated by using keys in the metadata document // that is uploaded for the SAML provider entity for your identity provider. // // Calling AssumeRoleWithSAML can result in an entry in your AWS CloudTrail // logs. The entry includes the value in the NameID element of the SAML assertion. // We recommend that you use a NameIDType that is not associated with any personally // identifiable information (PII). For example, you could instead use the Persistent // Identifier (urn:oasis:names:tc:SAML:2.0:nameid-format:persistent). // // For more information, see the following resources: // // About SAML 2.0-based Federation (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_saml.html) // in the IAM User Guide. // // Creating SAML Identity Providers (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml.html) // in the IAM User Guide. // // Configuring a Relying Party and Claims (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml_relying-party.html) // in the IAM User Guide. // // Creating a Role for SAML 2.0 Federation (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_saml.html) // in the IAM User Guide. func (c *STS) AssumeRoleWithSAML(input *AssumeRoleWithSAMLInput) (*AssumeRoleWithSAMLOutput, error) { req, out := c.AssumeRoleWithSAMLRequest(input) err := req.Send() return out, err } const opAssumeRoleWithWebIdentity = "AssumeRoleWithWebIdentity" // AssumeRoleWithWebIdentityRequest generates a "aws/request.Request" representing the // client's request for the AssumeRoleWithWebIdentity operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the AssumeRoleWithWebIdentity method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the AssumeRoleWithWebIdentityRequest method. // req, resp := client.AssumeRoleWithWebIdentityRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityInput) (req *request.Request, output *AssumeRoleWithWebIdentityOutput) { op := &request.Operation{ Name: opAssumeRoleWithWebIdentity, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &AssumeRoleWithWebIdentityInput{} } req = c.newRequest(op, input, output) output = &AssumeRoleWithWebIdentityOutput{} req.Data = output return } // Returns a set of temporary security credentials for users who have been authenticated // in a mobile or web application with a web identity provider, such as Amazon // Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible // identity provider. // // For mobile applications, we recommend that you use Amazon Cognito. You // can use Amazon Cognito with the AWS SDK for iOS (http://aws.amazon.com/sdkforios/) // and the AWS SDK for Android (http://aws.amazon.com/sdkforandroid/) to uniquely // identify a user and supply the user with a consistent identity throughout // the lifetime of an application. // // To learn more about Amazon Cognito, see Amazon Cognito Overview (http://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/cognito-auth.html#d0e840) // in the AWS SDK for Android Developer Guide guide and Amazon Cognito Overview // (http://docs.aws.amazon.com/mobile/sdkforios/developerguide/cognito-auth.html#d0e664) // in the AWS SDK for iOS Developer Guide. // // Calling AssumeRoleWithWebIdentity does not require the use of AWS security // credentials. Therefore, you can distribute an application (for example, on // mobile devices) that requests temporary security credentials without including // long-term AWS credentials in the application, and without deploying server-based // proxy services that use long-term AWS credentials. Instead, the identity // of the caller is validated by using a token from the web identity provider. // For a comparison of AssumeRoleWithWebIdentity with the other APIs that produce // temporary credentials, see Requesting Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) // and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // The temporary security credentials returned by this API consist of an access // key ID, a secret access key, and a security token. Applications can use these // temporary security credentials to sign calls to AWS service APIs. // // The credentials are valid for the duration that you specified when calling // AssumeRoleWithWebIdentity, which can be from 900 seconds (15 minutes) to // a maximum of 3600 seconds (1 hour). The default is 1 hour. // // The temporary security credentials created by AssumeRoleWithWebIdentity // can be used to make API calls to any AWS service with the following exception: // you cannot call the STS service's GetFederationToken or GetSessionToken APIs. // // Optionally, you can pass an IAM access policy to this operation. If you // choose not to pass a policy, the temporary security credentials that are // returned by the operation have the permissions that are defined in the access // policy of the role that is being assumed. If you pass a policy to this operation, // the temporary security credentials that are returned by the operation have // the permissions that are allowed by both the access policy of the role that // is being assumed, and the policy that you pass. This gives you a way to // further restrict the permissions for the resulting temporary security credentials. // You cannot use the passed policy to grant permissions that are in excess // of those allowed by the access policy of the role that is being assumed. // For more information, see Permissions for AssumeRole, AssumeRoleWithSAML, // and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) // in the IAM User Guide. // // Before your application can call AssumeRoleWithWebIdentity, you must have // an identity token from a supported identity provider and create a role that // the application can assume. The role that your application assumes must trust // the identity provider that is associated with the identity token. In other // words, the identity provider must be specified in the role's trust policy. // // Calling AssumeRoleWithWebIdentity can result in an entry in your AWS CloudTrail // logs. The entry includes the Subject (http://openid.net/specs/openid-connect-core-1_0.html#Claims) // of the provided Web Identity Token. We recommend that you avoid using any // personally identifiable information (PII) in this field. For example, you // could instead use a GUID or a pairwise identifier, as suggested in the OIDC // specification (http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes). // // For more information about how to use web identity federation and the AssumeRoleWithWebIdentity // API, see the following resources: // // Using Web Identity Federation APIs for Mobile Apps (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc_manual) // and Federation Through a Web-based Identity Provider (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity). // // Web Identity Federation Playground (https://web-identity-federation-playground.s3.amazonaws.com/index.html). // This interactive website lets you walk through the process of authenticating // via Login with Amazon, Facebook, or Google, getting temporary security credentials, // and then using those credentials to make a request to AWS. // // AWS SDK for iOS (http://aws.amazon.com/sdkforios/) and AWS SDK for Android // (http://aws.amazon.com/sdkforandroid/). These toolkits contain sample apps // that show how to invoke the identity providers, and then how to use the information // from these providers to get and use temporary security credentials. // // Web Identity Federation with Mobile Applications (http://aws.amazon.com/articles/4617974389850313). // This article discusses web identity federation and shows an example of how // to use web identity federation to get access to content in Amazon S3. func (c *STS) AssumeRoleWithWebIdentity(input *AssumeRoleWithWebIdentityInput) (*AssumeRoleWithWebIdentityOutput, error) { req, out := c.AssumeRoleWithWebIdentityRequest(input) err := req.Send() return out, err } const opDecodeAuthorizationMessage = "DecodeAuthorizationMessage" // DecodeAuthorizationMessageRequest generates a "aws/request.Request" representing the // client's request for the DecodeAuthorizationMessage operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the DecodeAuthorizationMessage method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the DecodeAuthorizationMessageRequest method. // req, resp := client.DecodeAuthorizationMessageRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *STS) DecodeAuthorizationMessageRequest(input *DecodeAuthorizationMessageInput) (req *request.Request, output *DecodeAuthorizationMessageOutput) { op := &request.Operation{ Name: opDecodeAuthorizationMessage, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &DecodeAuthorizationMessageInput{} } req = c.newRequest(op, input, output) output = &DecodeAuthorizationMessageOutput{} req.Data = output return } // Decodes additional information about the authorization status of a request // from an encoded message returned in response to an AWS request. // // For example, if a user is not authorized to perform an action that he or // she has requested, the request returns a Client.UnauthorizedOperation response // (an HTTP 403 response). Some AWS actions additionally return an encoded message // that can provide details about this authorization failure. // // Only certain AWS actions return an encoded authorization message. The documentation // for an individual action indicates whether that action returns an encoded // message in addition to returning an HTTP code. // // The message is encoded because the details of the authorization status // can constitute privileged information that the user who requested the action // should not see. To decode an authorization status message, a user must be // granted permissions via an IAM policy to request the DecodeAuthorizationMessage // (sts:DecodeAuthorizationMessage) action. // // The decoded message includes the following type of information: // // Whether the request was denied due to an explicit deny or due to the absence // of an explicit allow. For more information, see Determining Whether a Request // is Allowed or Denied (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html#policy-eval-denyallow) // in the IAM User Guide. // // The principal who made the request. // // The requested action. // // The requested resource. // // The values of condition keys in the context of the user's request. func (c *STS) DecodeAuthorizationMessage(input *DecodeAuthorizationMessageInput) (*DecodeAuthorizationMessageOutput, error) { req, out := c.DecodeAuthorizationMessageRequest(input) err := req.Send() return out, err } const opGetCallerIdentity = "GetCallerIdentity" // GetCallerIdentityRequest generates a "aws/request.Request" representing the // client's request for the GetCallerIdentity operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the GetCallerIdentity method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the GetCallerIdentityRequest method. // req, resp := client.GetCallerIdentityRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *STS) GetCallerIdentityRequest(input *GetCallerIdentityInput) (req *request.Request, output *GetCallerIdentityOutput) { op := &request.Operation{ Name: opGetCallerIdentity, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &GetCallerIdentityInput{} } req = c.newRequest(op, input, output) output = &GetCallerIdentityOutput{} req.Data = output return } // Returns details about the IAM identity whose credentials are used to call // the API. func (c *STS) GetCallerIdentity(input *GetCallerIdentityInput) (*GetCallerIdentityOutput, error) { req, out := c.GetCallerIdentityRequest(input) err := req.Send() return out, err } const opGetFederationToken = "GetFederationToken" // GetFederationTokenRequest generates a "aws/request.Request" representing the // client's request for the GetFederationToken operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the GetFederationToken method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the GetFederationTokenRequest method. // req, resp := client.GetFederationTokenRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *request.Request, output *GetFederationTokenOutput) { op := &request.Operation{ Name: opGetFederationToken, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &GetFederationTokenInput{} } req = c.newRequest(op, input, output) output = &GetFederationTokenOutput{} req.Data = output return } // Returns a set of temporary security credentials (consisting of an access // key ID, a secret access key, and a security token) for a federated user. // A typical use is in a proxy application that gets temporary security credentials // on behalf of distributed applications inside a corporate network. Because // you must call the GetFederationToken action using the long-term security // credentials of an IAM user, this call is appropriate in contexts where those // credentials can be safely stored, usually in a server-based application. // For a comparison of GetFederationToken with the other APIs that produce temporary // credentials, see Requesting Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) // and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // If you are creating a mobile-based or browser-based app that can authenticate // users using a web identity provider like Login with Amazon, Facebook, Google, // or an OpenID Connect-compatible identity provider, we recommend that you // use Amazon Cognito (http://aws.amazon.com/cognito/) or AssumeRoleWithWebIdentity. // For more information, see Federation Through a Web-based Identity Provider // (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity). // // The GetFederationToken action must be called by using the long-term AWS // security credentials of an IAM user. You can also call GetFederationToken // using the security credentials of an AWS root account, but we do not recommended // it. Instead, we recommend that you create an IAM user for the purpose of // the proxy application and then attach a policy to the IAM user that limits // federated users to only the actions and resources that they need access to. // For more information, see IAM Best Practices (http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) // in the IAM User Guide. // // The temporary security credentials that are obtained by using the long-term // credentials of an IAM user are valid for the specified duration, from 900 // seconds (15 minutes) up to a maximium of 129600 seconds (36 hours). The default // is 43200 seconds (12 hours). Temporary credentials that are obtained by using // AWS root account credentials have a maximum duration of 3600 seconds (1 hour). // // The temporary security credentials created by GetFederationToken can be // used to make API calls to any AWS service with the following exceptions: // // You cannot use these credentials to call any IAM APIs. // // You cannot call any STS APIs. // // Permissions // // The permissions for the temporary security credentials returned by GetFederationToken // are determined by a combination of the following: // // The policy or policies that are attached to the IAM user whose credentials // are used to call GetFederationToken. // // The policy that is passed as a parameter in the call. // // The passed policy is attached to the temporary security credentials that // result from the GetFederationToken API call--that is, to the federated user. // When the federated user makes an AWS request, AWS evaluates the policy attached // to the federated user in combination with the policy or policies attached // to the IAM user whose credentials were used to call GetFederationToken. AWS // allows the federated user's request only when both the federated user and // the IAM user are explicitly allowed to perform the requested action. The // passed policy cannot grant more permissions than those that are defined in // the IAM user policy. // // A typical use case is that the permissions of the IAM user whose credentials // are used to call GetFederationToken are designed to allow access to all the // actions and resources that any federated user will need. Then, for individual // users, you pass a policy to the operation that scopes down the permissions // to a level that's appropriate to that individual user, using a policy that // allows only a subset of permissions that are granted to the IAM user. // // If you do not pass a policy, the resulting temporary security credentials // have no effective permissions. The only exception is when the temporary security // credentials are used to access a resource that has a resource-based policy // that specifically allows the federated user to access the resource. // // For more information about how permissions work, see Permissions for GetFederationToken // (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getfederationtoken.html). // For information about using GetFederationToken to create temporary security // credentials, see GetFederationToken—Federation Through a Custom Identity // Broker (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken). func (c *STS) GetFederationToken(input *GetFederationTokenInput) (*GetFederationTokenOutput, error) { req, out := c.GetFederationTokenRequest(input) err := req.Send() return out, err } const opGetSessionToken = "GetSessionToken" // GetSessionTokenRequest generates a "aws/request.Request" representing the // client's request for the GetSessionToken operation. The "output" return // value can be used to capture response data after the request's "Send" method // is called. // // Creating a request object using this method should be used when you want to inject // custom logic into the request's lifecycle using a custom handler, or if you want to // access properties on the request object before or after sending the request. If // you just want the service response, call the GetSessionToken method directly // instead. // // Note: You must call the "Send" method on the returned request object in order // to execute the request. // // // Example sending a request using the GetSessionTokenRequest method. // req, resp := client.GetSessionTokenRequest(params) // // err := req.Send() // if err == nil { // resp is now filled // fmt.Println(resp) // } // func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.Request, output *GetSessionTokenOutput) { op := &request.Operation{ Name: opGetSessionToken, HTTPMethod: "POST", HTTPPath: "/", } if input == nil { input = &GetSessionTokenInput{} } req = c.newRequest(op, input, output) output = &GetSessionTokenOutput{} req.Data = output return } // Returns a set of temporary credentials for an AWS account or IAM user. The // credentials consist of an access key ID, a secret access key, and a security // token. Typically, you use GetSessionToken if you want to use MFA to protect // programmatic calls to specific AWS APIs like Amazon EC2 StopInstances. MFA-enabled // IAM users would need to call GetSessionToken and submit an MFA code that // is associated with their MFA device. Using the temporary security credentials // that are returned from the call, IAM users can then make programmatic calls // to APIs that require MFA authentication. If you do not supply a correct MFA // code, then the API returns an access denied error. For a comparison of GetSessionToken // with the other APIs that produce temporary credentials, see Requesting Temporary // Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) // and Comparing the AWS STS APIs (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // The GetSessionToken action must be called by using the long-term AWS security // credentials of the AWS account or an IAM user. Credentials that are created // by IAM users are valid for the duration that you specify, from 900 seconds // (15 minutes) up to a maximum of 129600 seconds (36 hours), with a default // of 43200 seconds (12 hours); credentials that are created by using account // credentials can range from 900 seconds (15 minutes) up to a maximum of 3600 // seconds (1 hour), with a default of 1 hour. // // The temporary security credentials created by GetSessionToken can be used // to make API calls to any AWS service with the following exceptions: // // You cannot call any IAM APIs unless MFA authentication information is // included in the request. // // You cannot call any STS API except AssumeRole. // // We recommend that you do not call GetSessionToken with root account credentials. // Instead, follow our best practices (http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) // by creating one or more IAM users, giving them the necessary permissions, // and using IAM users for everyday interaction with AWS. // // The permissions associated with the temporary security credentials returned // by GetSessionToken are based on the permissions associated with account or // IAM user whose credentials are used to call the action. If GetSessionToken // is called using root account credentials, the temporary credentials have // root account permissions. Similarly, if GetSessionToken is called using the // credentials of an IAM user, the temporary credentials have the same permissions // as the IAM user. // // For more information about using GetSessionToken to create temporary credentials, // go to Temporary Credentials for Users in Untrusted Environments (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getsessiontoken) // in the IAM User Guide. func (c *STS) GetSessionToken(input *GetSessionTokenInput) (*GetSessionTokenOutput, error) { req, out := c.GetSessionTokenRequest(input) err := req.Send() return out, err } type AssumeRoleInput struct { _ struct{} `type:"structure"` // The duration, in seconds, of the role session. The value can range from 900 // seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set // to 3600 seconds. // // This is separate from the duration of a console session that you might // request using the returned credentials. The request to the federation endpoint // for a console sign-in token takes a SessionDuration parameter that specifies // the maximum length of the console session, separately from the DurationSeconds // parameter on this API. For more information, see Creating a URL that Enables // Federated Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) // in the IAM User Guide. DurationSeconds *int64 `min:"900" type:"integer"` // A unique identifier that is used by third parties when assuming roles in // their customers' accounts. For each role that the third party can assume, // they should instruct their customers to ensure the role's trust policy checks // for the external ID that the third party generated. Each time the third party // assumes the role, they should pass the customer's external ID. The external // ID is useful in order to help third parties bind a role to the customer who // created it. For more information about the external ID, see How to Use an // External ID When Granting Access to Your AWS Resources to a Third Party (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) // in the IAM User Guide. // // The format for this parameter, as described by its regex pattern, is a string // of characters consisting of upper- and lower-case alphanumeric characters // with no spaces. You can also include underscores or any of the following // characters: =,.@:\/- ExternalId *string `min:"2" type:"string"` // An IAM policy in JSON format. // // This parameter is optional. If you pass a policy, the temporary security // credentials that are returned by the operation have the permissions that // are allowed by both (the intersection of) the access policy of the role that // is being assumed, and the policy that you pass. This gives you a way to further // restrict the permissions for the resulting temporary security credentials. // You cannot use the passed policy to grant permissions that are in excess // of those allowed by the access policy of the role that is being assumed. // For more information, see Permissions for AssumeRole, AssumeRoleWithSAML, // and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) // in the IAM User Guide. // // The format for this parameter, as described by its regex pattern, is a string // of characters up to 2048 characters in length. The characters can be any // ASCII character from the space character to the end of the valid character // list (\u0020-\u00FF). It can also include the tab (\u0009), linefeed (\u000A), // and carriage return (\u000D) characters. // // The policy plain text must be 2048 bytes or shorter. However, an internal // conversion compresses it into a packed binary format with a separate limit. // The PackedPolicySize response element indicates by percentage how close to // the upper size limit the policy is, with 100% equaling the maximum allowed // size. Policy *string `min:"1" type:"string"` // The Amazon Resource Name (ARN) of the role to assume. RoleArn *string `min:"20" type:"string" required:"true"` // An identifier for the assumed role session. // // Use the role session name to uniquely identify a session when the same role // is assumed by different principals or for different reasons. In cross-account // scenarios, the role session name is visible to, and can be logged by the // account that owns the role. The role session name is also used in the ARN // of the assumed role principal. This means that subsequent cross-account API // requests using the temporary security credentials will expose the role session // name to the external account in their CloudTrail logs. // // The format for this parameter, as described by its regex pattern, is a string // of characters consisting of upper- and lower-case alphanumeric characters // with no spaces. You can also include underscores or any of the following // characters: =,.@- RoleSessionName *string `min:"2" type:"string" required:"true"` // The identification number of the MFA device that is associated with the user // who is making the AssumeRole call. Specify this value if the trust policy // of the role being assumed includes a condition that requires MFA authentication. // The value is either the serial number for a hardware device (such as GAHT12345678) // or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user). // // The format for this parameter, as described by its regex pattern, is a string // of characters consisting of upper- and lower-case alphanumeric characters // with no spaces. You can also include underscores or any of the following // characters: =,.@- SerialNumber *string `min:"9" type:"string"` // The value provided by the MFA device, if the trust policy of the role being // assumed requires MFA (that is, if the policy includes a condition that tests // for MFA). If the role being assumed requires MFA and if the TokenCode value // is missing or expired, the AssumeRole call returns an "access denied" error. // // The format for this parameter, as described by its regex pattern, is a sequence // of six numeric digits. TokenCode *string `min:"6" type:"string"` } // String returns the string representation func (s AssumeRoleInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s AssumeRoleInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *AssumeRoleInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "AssumeRoleInput"} if s.DurationSeconds != nil && *s.DurationSeconds < 900 { invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) } if s.ExternalId != nil && len(*s.ExternalId) < 2 { invalidParams.Add(request.NewErrParamMinLen("ExternalId", 2)) } if s.Policy != nil && len(*s.Policy) < 1 { invalidParams.Add(request.NewErrParamMinLen("Policy", 1)) } if s.RoleArn == nil { invalidParams.Add(request.NewErrParamRequired("RoleArn")) } if s.RoleArn != nil && len(*s.RoleArn) < 20 { invalidParams.Add(request.NewErrParamMinLen("RoleArn", 20)) } if s.RoleSessionName == nil { invalidParams.Add(request.NewErrParamRequired("RoleSessionName")) } if s.RoleSessionName != nil && len(*s.RoleSessionName) < 2 { invalidParams.Add(request.NewErrParamMinLen("RoleSessionName", 2)) } if s.SerialNumber != nil && len(*s.SerialNumber) < 9 { invalidParams.Add(request.NewErrParamMinLen("SerialNumber", 9)) } if s.TokenCode != nil && len(*s.TokenCode) < 6 { invalidParams.Add(request.NewErrParamMinLen("TokenCode", 6)) } if invalidParams.Len() > 0 { return invalidParams } return nil } // Contains the response to a successful AssumeRole request, including temporary // AWS credentials that can be used to make AWS requests. type AssumeRoleOutput struct { _ struct{} `type:"structure"` // The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers // that you can use to refer to the resulting temporary security credentials. // For example, you can reference these credentials as a principal in a resource-based // policy by using the ARN or assumed role ID. The ARN and ID include the RoleSessionName // that you specified when you called AssumeRole. AssumedRoleUser *AssumedRoleUser `type:"structure"` // The temporary security credentials, which include an access key ID, a secret // access key, and a security (or session) token. // // Note: The size of the security token that STS APIs return is not fixed. // We strongly recommend that you make no assumptions about the maximum size. // As of this writing, the typical size is less than 4096 bytes, but that can // vary. Also, future updates to AWS might require larger sizes. Credentials *Credentials `type:"structure"` // A percentage value that indicates the size of the policy in packed form. // The service rejects any policy with a packed size greater than 100 percent, // which means the policy exceeded the allowed space. PackedPolicySize *int64 `type:"integer"` } // String returns the string representation func (s AssumeRoleOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s AssumeRoleOutput) GoString() string { return s.String() } type AssumeRoleWithSAMLInput struct { _ struct{} `type:"structure"` // The duration, in seconds, of the role session. The value can range from 900 // seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set // to 3600 seconds. An expiration can also be specified in the SAML authentication // response's SessionNotOnOrAfter value. The actual expiration time is whichever // value is shorter. // // This is separate from the duration of a console session that you might // request using the returned credentials. The request to the federation endpoint // for a console sign-in token takes a SessionDuration parameter that specifies // the maximum length of the console session, separately from the DurationSeconds // parameter on this API. For more information, see Enabling SAML 2.0 Federated // Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-saml.html) // in the IAM User Guide. DurationSeconds *int64 `min:"900" type:"integer"` // An IAM policy in JSON format. // // The policy parameter is optional. If you pass a policy, the temporary security // credentials that are returned by the operation have the permissions that // are allowed by both the access policy of the role that is being assumed, // and the policy that you pass. This gives you a way to further restrict // the permissions for the resulting temporary security credentials. You cannot // use the passed policy to grant permissions that are in excess of those allowed // by the access policy of the role that is being assumed. For more information, // Permissions for AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity // (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) // in the IAM User Guide. // // The format for this parameter, as described by its regex pattern, is a string // of characters up to 2048 characters in length. The characters can be any // ASCII character from the space character to the end of the valid character // list (\u0020-\u00FF). It can also include the tab (\u0009), linefeed (\u000A), // and carriage return (\u000D) characters. // // The policy plain text must be 2048 bytes or shorter. However, an internal // conversion compresses it into a packed binary format with a separate limit. // The PackedPolicySize response element indicates by percentage how close to // the upper size limit the policy is, with 100% equaling the maximum allowed // size. Policy *string `min:"1" type:"string"` // The Amazon Resource Name (ARN) of the SAML provider in IAM that describes // the IdP. PrincipalArn *string `min:"20" type:"string" required:"true"` // The Amazon Resource Name (ARN) of the role that the caller is assuming. RoleArn *string `min:"20" type:"string" required:"true"` // The base-64 encoded SAML authentication response provided by the IdP. // // For more information, see Configuring a Relying Party and Adding Claims // (http://docs.aws.amazon.com/IAM/latest/UserGuide/create-role-saml-IdP-tasks.html) // in the Using IAM guide. SAMLAssertion *string `min:"4" type:"string" required:"true"` } // String returns the string representation func (s AssumeRoleWithSAMLInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s AssumeRoleWithSAMLInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *AssumeRoleWithSAMLInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "AssumeRoleWithSAMLInput"} if s.DurationSeconds != nil && *s.DurationSeconds < 900 { invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) } if s.Policy != nil && len(*s.Policy) < 1 { invalidParams.Add(request.NewErrParamMinLen("Policy", 1)) } if s.PrincipalArn == nil { invalidParams.Add(request.NewErrParamRequired("PrincipalArn")) } if s.PrincipalArn != nil && len(*s.PrincipalArn) < 20 { invalidParams.Add(request.NewErrParamMinLen("PrincipalArn", 20)) } if s.RoleArn == nil { invalidParams.Add(request.NewErrParamRequired("RoleArn")) } if s.RoleArn != nil && len(*s.RoleArn) < 20 { invalidParams.Add(request.NewErrParamMinLen("RoleArn", 20)) } if s.SAMLAssertion == nil { invalidParams.Add(request.NewErrParamRequired("SAMLAssertion")) } if s.SAMLAssertion != nil && len(*s.SAMLAssertion) < 4 { invalidParams.Add(request.NewErrParamMinLen("SAMLAssertion", 4)) } if invalidParams.Len() > 0 { return invalidParams } return nil } // Contains the response to a successful AssumeRoleWithSAML request, including // temporary AWS credentials that can be used to make AWS requests. type AssumeRoleWithSAMLOutput struct { _ struct{} `type:"structure"` // The identifiers for the temporary security credentials that the operation // returns. AssumedRoleUser *AssumedRoleUser `type:"structure"` // The value of the Recipient attribute of the SubjectConfirmationData element // of the SAML assertion. Audience *string `type:"string"` // The temporary security credentials, which include an access key ID, a secret // access key, and a security (or session) token. // // Note: The size of the security token that STS APIs return is not fixed. // We strongly recommend that you make no assumptions about the maximum size. // As of this writing, the typical size is less than 4096 bytes, but that can // vary. Also, future updates to AWS might require larger sizes. Credentials *Credentials `type:"structure"` // The value of the Issuer element of the SAML assertion. Issuer *string `type:"string"` // A hash value based on the concatenation of the Issuer response value, the // AWS account ID, and the friendly name (the last part of the ARN) of the SAML // provider in IAM. The combination of NameQualifier and Subject can be used // to uniquely identify a federated user. // // The following pseudocode shows how the hash value is calculated: // // BASE64 ( SHA1 ( "https://example.com/saml" + "123456789012" + "/MySAMLIdP" // ) ) NameQualifier *string `type:"string"` // A percentage value that indicates the size of the policy in packed form. // The service rejects any policy with a packed size greater than 100 percent, // which means the policy exceeded the allowed space. PackedPolicySize *int64 `type:"integer"` // The value of the NameID element in the Subject element of the SAML assertion. Subject *string `type:"string"` // The format of the name ID, as defined by the Format attribute in the NameID // element of the SAML assertion. Typical examples of the format are transient // or persistent. // // If the format includes the prefix urn:oasis:names:tc:SAML:2.0:nameid-format, // that prefix is removed. For example, urn:oasis:names:tc:SAML:2.0:nameid-format:transient // is returned as transient. If the format includes any other prefix, the format // is returned with no modifications. SubjectType *string `type:"string"` } // String returns the string representation func (s AssumeRoleWithSAMLOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s AssumeRoleWithSAMLOutput) GoString() string { return s.String() } type AssumeRoleWithWebIdentityInput struct { _ struct{} `type:"structure"` // The duration, in seconds, of the role session. The value can range from 900 // seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set // to 3600 seconds. // // This is separate from the duration of a console session that you might // request using the returned credentials. The request to the federation endpoint // for a console sign-in token takes a SessionDuration parameter that specifies // the maximum length of the console session, separately from the DurationSeconds // parameter on this API. For more information, see Creating a URL that Enables // Federated Users to Access the AWS Management Console (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) // in the IAM User Guide. DurationSeconds *int64 `min:"900" type:"integer"` // An IAM policy in JSON format. // // The policy parameter is optional. If you pass a policy, the temporary security // credentials that are returned by the operation have the permissions that // are allowed by both the access policy of the role that is being assumed, // and the policy that you pass. This gives you a way to further restrict // the permissions for the resulting temporary security credentials. You cannot // use the passed policy to grant permissions that are in excess of those allowed // by the access policy of the role that is being assumed. For more information, // see Permissions for AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html) // in the IAM User Guide. // // The format for this parameter, as described by its regex pattern, is a string // of characters up to 2048 characters in length. The characters can be any // ASCII character from the space character to the end of the valid character // list (\u0020-\u00FF). It can also include the tab (\u0009), linefeed (\u000A), // and carriage return (\u000D) characters. // // The policy plain text must be 2048 bytes or shorter. However, an internal // conversion compresses it into a packed binary format with a separate limit. // The PackedPolicySize response element indicates by percentage how close to // the upper size limit the policy is, with 100% equaling the maximum allowed // size. Policy *string `min:"1" type:"string"` // The fully qualified host component of the domain name of the identity provider. // // Specify this value only for OAuth 2.0 access tokens. Currently www.amazon.com // and graph.facebook.com are the only supported identity providers for OAuth // 2.0 access tokens. Do not include URL schemes and port numbers. // // Do not specify this value for OpenID Connect ID tokens. ProviderId *string `min:"4" type:"string"` // The Amazon Resource Name (ARN) of the role that the caller is assuming. RoleArn *string `min:"20" type:"string" required:"true"` // An identifier for the assumed role session. Typically, you pass the name // or identifier that is associated with the user who is using your application. // That way, the temporary security credentials that your application will use // are associated with that user. This session name is included as part of the // ARN and assumed role ID in the AssumedRoleUser response element. // // The format for this parameter, as described by its regex pattern, is a string // of characters consisting of upper- and lower-case alphanumeric characters // with no spaces. You can also include underscores or any of the following // characters: =,.@- RoleSessionName *string `min:"2" type:"string" required:"true"` // The OAuth 2.0 access token or OpenID Connect ID token that is provided by // the identity provider. Your application must get this token by authenticating // the user who is using your application with a web identity provider before // the application makes an AssumeRoleWithWebIdentity call. WebIdentityToken *string `min:"4" type:"string" required:"true"` } // String returns the string representation func (s AssumeRoleWithWebIdentityInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s AssumeRoleWithWebIdentityInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *AssumeRoleWithWebIdentityInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "AssumeRoleWithWebIdentityInput"} if s.DurationSeconds != nil && *s.DurationSeconds < 900 { invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) } if s.Policy != nil && len(*s.Policy) < 1 { invalidParams.Add(request.NewErrParamMinLen("Policy", 1)) } if s.ProviderId != nil && len(*s.ProviderId) < 4 { invalidParams.Add(request.NewErrParamMinLen("ProviderId", 4)) } if s.RoleArn == nil { invalidParams.Add(request.NewErrParamRequired("RoleArn")) } if s.RoleArn != nil && len(*s.RoleArn) < 20 { invalidParams.Add(request.NewErrParamMinLen("RoleArn", 20)) } if s.RoleSessionName == nil { invalidParams.Add(request.NewErrParamRequired("RoleSessionName")) } if s.RoleSessionName != nil && len(*s.RoleSessionName) < 2 { invalidParams.Add(request.NewErrParamMinLen("RoleSessionName", 2)) } if s.WebIdentityToken == nil { invalidParams.Add(request.NewErrParamRequired("WebIdentityToken")) } if s.WebIdentityToken != nil && len(*s.WebIdentityToken) < 4 { invalidParams.Add(request.NewErrParamMinLen("WebIdentityToken", 4)) } if invalidParams.Len() > 0 { return invalidParams } return nil } // Contains the response to a successful AssumeRoleWithWebIdentity request, // including temporary AWS credentials that can be used to make AWS requests. type AssumeRoleWithWebIdentityOutput struct { _ struct{} `type:"structure"` // The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers // that you can use to refer to the resulting temporary security credentials. // For example, you can reference these credentials as a principal in a resource-based // policy by using the ARN or assumed role ID. The ARN and ID include the RoleSessionName // that you specified when you called AssumeRole. AssumedRoleUser *AssumedRoleUser `type:"structure"` // The intended audience (also known as client ID) of the web identity token. // This is traditionally the client identifier issued to the application that // requested the web identity token. Audience *string `type:"string"` // The temporary security credentials, which include an access key ID, a secret // access key, and a security token. // // Note: The size of the security token that STS APIs return is not fixed. // We strongly recommend that you make no assumptions about the maximum size. // As of this writing, the typical size is less than 4096 bytes, but that can // vary. Also, future updates to AWS might require larger sizes. Credentials *Credentials `type:"structure"` // A percentage value that indicates the size of the policy in packed form. // The service rejects any policy with a packed size greater than 100 percent, // which means the policy exceeded the allowed space. PackedPolicySize *int64 `type:"integer"` // The issuing authority of the web identity token presented. For OpenID Connect // ID Tokens this contains the value of the iss field. For OAuth 2.0 access // tokens, this contains the value of the ProviderId parameter that was passed // in the AssumeRoleWithWebIdentity request. Provider *string `type:"string"` // The unique user identifier that is returned by the identity provider. This // identifier is associated with the WebIdentityToken that was submitted with // the AssumeRoleWithWebIdentity call. The identifier is typically unique to // the user and the application that acquired the WebIdentityToken (pairwise // identifier). For OpenID Connect ID tokens, this field contains the value // returned by the identity provider as the token's sub (Subject) claim. SubjectFromWebIdentityToken *string `min:"6" type:"string"` } // String returns the string representation func (s AssumeRoleWithWebIdentityOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s AssumeRoleWithWebIdentityOutput) GoString() string { return s.String() } // The identifiers for the temporary security credentials that the operation // returns. type AssumedRoleUser struct { _ struct{} `type:"structure"` // The ARN of the temporary security credentials that are returned from the // AssumeRole action. For more information about ARNs and how to use them in // policies, see IAM Identifiers (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html) // in Using IAM. Arn *string `min:"20" type:"string" required:"true"` // A unique identifier that contains the role ID and the role session name of // the role that is being assumed. The role ID is generated by AWS when the // role is created. AssumedRoleId *string `min:"2" type:"string" required:"true"` } // String returns the string representation func (s AssumedRoleUser) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s AssumedRoleUser) GoString() string { return s.String() } // AWS credentials for API authentication. type Credentials struct { _ struct{} `type:"structure"` // The access key ID that identifies the temporary security credentials. AccessKeyId *string `min:"16" type:"string" required:"true"` // The date on which the current credentials expire. Expiration *time.Time `type:"timestamp" timestampFormat:"iso8601" required:"true"` // The secret access key that can be used to sign requests. SecretAccessKey *string `type:"string" required:"true"` // The token that users must pass to the service API to use the temporary credentials. SessionToken *string `type:"string" required:"true"` } // String returns the string representation func (s Credentials) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s Credentials) GoString() string { return s.String() } type DecodeAuthorizationMessageInput struct { _ struct{} `type:"structure"` // The encoded message that was returned with the response. EncodedMessage *string `min:"1" type:"string" required:"true"` } // String returns the string representation func (s DecodeAuthorizationMessageInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DecodeAuthorizationMessageInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *DecodeAuthorizationMessageInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "DecodeAuthorizationMessageInput"} if s.EncodedMessage == nil { invalidParams.Add(request.NewErrParamRequired("EncodedMessage")) } if s.EncodedMessage != nil && len(*s.EncodedMessage) < 1 { invalidParams.Add(request.NewErrParamMinLen("EncodedMessage", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } // A document that contains additional information about the authorization status // of a request from an encoded message that is returned in response to an AWS // request. type DecodeAuthorizationMessageOutput struct { _ struct{} `type:"structure"` // An XML document that contains the decoded message. DecodedMessage *string `type:"string"` } // String returns the string representation func (s DecodeAuthorizationMessageOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s DecodeAuthorizationMessageOutput) GoString() string { return s.String() } // Identifiers for the federated user that is associated with the credentials. type FederatedUser struct { _ struct{} `type:"structure"` // The ARN that specifies the federated user that is associated with the credentials. // For more information about ARNs and how to use them in policies, see IAM // Identifiers (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html) // in Using IAM. Arn *string `min:"20" type:"string" required:"true"` // The string that identifies the federated user associated with the credentials, // similar to the unique ID of an IAM user. FederatedUserId *string `min:"2" type:"string" required:"true"` } // String returns the string representation func (s FederatedUser) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s FederatedUser) GoString() string { return s.String() } type GetCallerIdentityInput struct { _ struct{} `type:"structure"` } // String returns the string representation func (s GetCallerIdentityInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s GetCallerIdentityInput) GoString() string { return s.String() } // Contains the response to a successful GetCallerIdentity request, including // information about the entity making the request. type GetCallerIdentityOutput struct { _ struct{} `type:"structure"` // The AWS account ID number of the account that owns or contains the calling // entity. Account *string `type:"string"` // The AWS ARN associated with the calling entity. Arn *string `min:"20" type:"string"` // The unique identifier of the calling entity. The exact value depends on the // type of entity making the call. The values returned are those listed in the // aws:userid column in the Principal table (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable) // found on the Policy Variables reference page in the IAM User Guide. UserId *string `type:"string"` } // String returns the string representation func (s GetCallerIdentityOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s GetCallerIdentityOutput) GoString() string { return s.String() } type GetFederationTokenInput struct { _ struct{} `type:"structure"` // The duration, in seconds, that the session should last. Acceptable durations // for federation sessions range from 900 seconds (15 minutes) to 129600 seconds // (36 hours), with 43200 seconds (12 hours) as the default. Sessions obtained // using AWS account (root) credentials are restricted to a maximum of 3600 // seconds (one hour). If the specified duration is longer than one hour, the // session obtained by using AWS account (root) credentials defaults to one // hour. DurationSeconds *int64 `min:"900" type:"integer"` // The name of the federated user. The name is used as an identifier for the // temporary security credentials (such as Bob). For example, you can reference // the federated user name in a resource-based policy, such as in an Amazon // S3 bucket policy. // // The format for this parameter, as described by its regex pattern, is a string // of characters consisting of upper- and lower-case alphanumeric characters // with no spaces. You can also include underscores or any of the following // characters: =,.@- Name *string `min:"2" type:"string" required:"true"` // An IAM policy in JSON format that is passed with the GetFederationToken call // and evaluated along with the policy or policies that are attached to the // IAM user whose credentials are used to call GetFederationToken. The passed // policy is used to scope down the permissions that are available to the IAM // user, by allowing only a subset of the permissions that are granted to the // IAM user. The passed policy cannot grant more permissions than those granted // to the IAM user. The final permissions for the federated user are the most // restrictive set based on the intersection of the passed policy and the IAM // user policy. // // If you do not pass a policy, the resulting temporary security credentials // have no effective permissions. The only exception is when the temporary security // credentials are used to access a resource that has a resource-based policy // that specifically allows the federated user to access the resource. // // The format for this parameter, as described by its regex pattern, is a string // of characters up to 2048 characters in length. The characters can be any // ASCII character from the space character to the end of the valid character // list (\u0020-\u00FF). It can also include the tab (\u0009), linefeed (\u000A), // and carriage return (\u000D) characters. // // The policy plain text must be 2048 bytes or shorter. However, an internal // conversion compresses it into a packed binary format with a separate limit. // The PackedPolicySize response element indicates by percentage how close to // the upper size limit the policy is, with 100% equaling the maximum allowed // size. // // For more information about how permissions work, see Permissions for GetFederationToken // (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getfederationtoken.html). Policy *string `min:"1" type:"string"` } // String returns the string representation func (s GetFederationTokenInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s GetFederationTokenInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *GetFederationTokenInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "GetFederationTokenInput"} if s.DurationSeconds != nil && *s.DurationSeconds < 900 { invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) } if s.Name == nil { invalidParams.Add(request.NewErrParamRequired("Name")) } if s.Name != nil && len(*s.Name) < 2 { invalidParams.Add(request.NewErrParamMinLen("Name", 2)) } if s.Policy != nil && len(*s.Policy) < 1 { invalidParams.Add(request.NewErrParamMinLen("Policy", 1)) } if invalidParams.Len() > 0 { return invalidParams } return nil } // Contains the response to a successful GetFederationToken request, including // temporary AWS credentials that can be used to make AWS requests. type GetFederationTokenOutput struct { _ struct{} `type:"structure"` // The temporary security credentials, which include an access key ID, a secret // access key, and a security (or session) token. // // Note: The size of the security token that STS APIs return is not fixed. // We strongly recommend that you make no assumptions about the maximum size. // As of this writing, the typical size is less than 4096 bytes, but that can // vary. Also, future updates to AWS might require larger sizes. Credentials *Credentials `type:"structure"` // Identifiers for the federated user associated with the credentials (such // as arn:aws:sts::123456789012:federated-user/Bob or 123456789012:Bob). You // can use the federated user's ARN in your resource-based policies, such as // an Amazon S3 bucket policy. FederatedUser *FederatedUser `type:"structure"` // A percentage value indicating the size of the policy in packed form. The // service rejects policies for which the packed size is greater than 100 percent // of the allowed value. PackedPolicySize *int64 `type:"integer"` } // String returns the string representation func (s GetFederationTokenOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s GetFederationTokenOutput) GoString() string { return s.String() } type GetSessionTokenInput struct { _ struct{} `type:"structure"` // The duration, in seconds, that the credentials should remain valid. Acceptable // durations for IAM user sessions range from 900 seconds (15 minutes) to 129600 // seconds (36 hours), with 43200 seconds (12 hours) as the default. Sessions // for AWS account owners are restricted to a maximum of 3600 seconds (one hour). // If the duration is longer than one hour, the session for AWS account owners // defaults to one hour. DurationSeconds *int64 `min:"900" type:"integer"` // The identification number of the MFA device that is associated with the IAM // user who is making the GetSessionToken call. Specify this value if the IAM // user has a policy that requires MFA authentication. The value is either the // serial number for a hardware device (such as GAHT12345678) or an Amazon Resource // Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user). // You can find the device for an IAM user by going to the AWS Management Console // and viewing the user's security credentials. // // The format for this parameter, as described by its regex pattern, is a string // of characters consisting of upper- and lower-case alphanumeric characters // with no spaces. You can also include underscores or any of the following // characters: =,.@- SerialNumber *string `min:"9" type:"string"` // The value provided by the MFA device, if MFA is required. If any policy requires // the IAM user to submit an MFA code, specify this value. If MFA authentication // is required, and the user does not provide a code when requesting a set of // temporary security credentials, the user will receive an "access denied" // response when requesting resources that require MFA authentication. // // The format for this parameter, as described by its regex pattern, is a sequence // of six numeric digits. TokenCode *string `min:"6" type:"string"` } // String returns the string representation func (s GetSessionTokenInput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s GetSessionTokenInput) GoString() string { return s.String() } // Validate inspects the fields of the type to determine if they are valid. func (s *GetSessionTokenInput) Validate() error { invalidParams := request.ErrInvalidParams{Context: "GetSessionTokenInput"} if s.DurationSeconds != nil && *s.DurationSeconds < 900 { invalidParams.Add(request.NewErrParamMinValue("DurationSeconds", 900)) } if s.SerialNumber != nil && len(*s.SerialNumber) < 9 { invalidParams.Add(request.NewErrParamMinLen("SerialNumber", 9)) } if s.TokenCode != nil && len(*s.TokenCode) < 6 { invalidParams.Add(request.NewErrParamMinLen("TokenCode", 6)) } if invalidParams.Len() > 0 { return invalidParams } return nil } // Contains the response to a successful GetSessionToken request, including // temporary AWS credentials that can be used to make AWS requests. type GetSessionTokenOutput struct { _ struct{} `type:"structure"` // The temporary security credentials, which include an access key ID, a secret // access key, and a security (or session) token. // // Note: The size of the security token that STS APIs return is not fixed. // We strongly recommend that you make no assumptions about the maximum size. // As of this writing, the typical size is less than 4096 bytes, but that can // vary. Also, future updates to AWS might require larger sizes. Credentials *Credentials `type:"structure"` } // String returns the string representation func (s GetSessionTokenOutput) String() string { return awsutil.Prettify(s) } // GoString returns the string representation func (s GetSessionTokenOutput) GoString() string { return s.String() } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/service/sts/customizations.go ================================================ package sts import "github.com/aws/aws-sdk-go/aws/request" func init() { initRequest = func(r *request.Request) { switch r.Operation.Name { case opAssumeRoleWithSAML, opAssumeRoleWithWebIdentity: r.Handlers.Sign.Clear() // these operations are unsigned } } } ================================================ FILE: vendor/github.com/aws/aws-sdk-go/service/sts/service.go ================================================ // THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. package sts import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/client/metadata" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/signer/v4" "github.com/aws/aws-sdk-go/private/protocol/query" ) // The AWS Security Token Service (STS) is a web service that enables you to // request temporary, limited-privilege credentials for AWS Identity and Access // Management (IAM) users or for users that you authenticate (federated users). // This guide provides descriptions of the STS API. For more detailed information // about using this service, go to Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html). // // As an alternative to using the API, you can use one of the AWS SDKs, which // consist of libraries and sample code for various programming languages and // platforms (Java, Ruby, .NET, iOS, Android, etc.). The SDKs provide a convenient // way to create programmatic access to STS. For example, the SDKs take care // of cryptographically signing requests, managing errors, and retrying requests // automatically. For information about the AWS SDKs, including how to download // and install them, see the Tools for Amazon Web Services page (http://aws.amazon.com/tools/). // // For information about setting up signatures and authorization through the // API, go to Signing AWS API Requests (http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html) // in the AWS General Reference. For general information about the Query API, // go to Making Query Requests (http://docs.aws.amazon.com/IAM/latest/UserGuide/IAM_UsingQueryAPI.html) // in Using IAM. For information about using security tokens with other AWS // products, go to AWS Services That Work with IAM (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html) // in the IAM User Guide. // // If you're new to AWS and need additional technical information about a specific // AWS product, you can find the product's technical documentation at http://aws.amazon.com/documentation/ // (http://aws.amazon.com/documentation/). // // Endpoints // // The AWS Security Token Service (STS) has a default endpoint of https://sts.amazonaws.com // that maps to the US East (N. Virginia) region. Additional regions are available // and are activated by default. For more information, see Activating and Deactivating // AWS STS in an AWS Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // // For information about STS endpoints, see Regions and Endpoints (http://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region) // in the AWS General Reference. // // Recording API requests // // STS supports AWS CloudTrail, which is a service that records AWS calls for // your AWS account and delivers log files to an Amazon S3 bucket. By using // information collected by CloudTrail, you can determine what requests were // successfully made to STS, who made the request, when it was made, and so // on. To learn more about CloudTrail, including how to turn it on and find // your log files, see the AWS CloudTrail User Guide (http://docs.aws.amazon.com/awscloudtrail/latest/userguide/what_is_cloud_trail_top_level.html). //The service client's operations are safe to be used concurrently. // It is not safe to mutate any of the client's properties though. type STS struct { *client.Client } // Used for custom client initialization logic var initClient func(*client.Client) // Used for custom request initialization logic var initRequest func(*request.Request) // A ServiceName is the name of the service the client will make API calls to. const ServiceName = "sts" // New creates a new instance of the STS client with a session. // If additional configuration is needed for the client instance use the optional // aws.Config parameter to add your extra config. // // Example: // // Create a STS client from just a session. // svc := sts.New(mySession) // // // Create a STS client with additional configuration // svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2")) func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS { c := p.ClientConfig(ServiceName, cfgs...) return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion) } // newClient creates, initializes and returns a new service client instance. func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *STS { svc := &STS{ Client: client.New( cfg, metadata.ClientInfo{ ServiceName: ServiceName, SigningRegion: signingRegion, Endpoint: endpoint, APIVersion: "2011-06-15", }, handlers, ), } // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) // Run custom client initialization if present if initClient != nil { initClient(svc.Client) } return svc } // newRequest creates a new request for a STS operation and runs any // custom request initialization. func (c *STS) newRequest(op *request.Operation, params, data interface{}) *request.Request { req := c.NewRequest(op, params, data) // Run custom request initialization if present if initRequest != nil { initRequest(req) } return req } ================================================ FILE: vendor/github.com/coreos/go-systemd/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/coreos/go-systemd/sdjournal/functions.go ================================================ // Copyright 2015 RedHat, Inc. // Copyright 2015 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sdjournal import ( "github.com/coreos/pkg/dlopen" "sync" "unsafe" ) var ( // lazy initialized libsystemdHandle *dlopen.LibHandle libsystemdMutex = &sync.Mutex{} libsystemdFunctions = map[string]unsafe.Pointer{} libsystemdNames = []string{ // systemd < 209 "libsystemd-journal.so.0", "libsystemd-journal.so", // systemd >= 209 merged libsystemd-journal into libsystemd proper "libsystemd.so.0", "libsystemd.so", } ) func getFunction(name string) (unsafe.Pointer, error) { libsystemdMutex.Lock() defer libsystemdMutex.Unlock() if libsystemdHandle == nil { h, err := dlopen.GetHandle(libsystemdNames) if err != nil { return nil, err } libsystemdHandle = h } f, ok := libsystemdFunctions[name] if !ok { var err error f, err = libsystemdHandle.GetSymbolPointer(name) if err != nil { return nil, err } libsystemdFunctions[name] = f } return f, nil } ================================================ FILE: vendor/github.com/coreos/go-systemd/sdjournal/journal.go ================================================ // Copyright 2015 RedHat, Inc. // Copyright 2015 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package sdjournal provides a low-level Go interface to the // systemd journal wrapped around the sd-journal C API. // // All public read methods map closely to the sd-journal API functions. See the // sd-journal.h documentation[1] for information about each function. // // To write to the journal, see the pure-Go "journal" package // // [1] http://www.freedesktop.org/software/systemd/man/sd-journal.html package sdjournal // #include // #include // #include // #include // // int // my_sd_journal_open(void *f, sd_journal **ret, int flags) // { // int (*sd_journal_open)(sd_journal **, int); // // sd_journal_open = f; // return sd_journal_open(ret, flags); // } // // int // my_sd_journal_open_directory(void *f, sd_journal **ret, const char *path, int flags) // { // int (*sd_journal_open_directory)(sd_journal **, const char *, int); // // sd_journal_open_directory = f; // return sd_journal_open_directory(ret, path, flags); // } // // void // my_sd_journal_close(void *f, sd_journal *j) // { // int (*sd_journal_close)(sd_journal *); // // sd_journal_close = f; // sd_journal_close(j); // } // // int // my_sd_journal_get_usage(void *f, sd_journal *j, uint64_t *bytes) // { // int (*sd_journal_get_usage)(sd_journal *, uint64_t *); // // sd_journal_get_usage = f; // return sd_journal_get_usage(j, bytes); // } // // int // my_sd_journal_add_match(void *f, sd_journal *j, const void *data, size_t size) // { // int (*sd_journal_add_match)(sd_journal *, const void *, size_t); // // sd_journal_add_match = f; // return sd_journal_add_match(j, data, size); // } // // int // my_sd_journal_add_disjunction(void *f, sd_journal *j) // { // int (*sd_journal_add_disjunction)(sd_journal *); // // sd_journal_add_disjunction = f; // return sd_journal_add_disjunction(j); // } // // int // my_sd_journal_add_conjunction(void *f, sd_journal *j) // { // int (*sd_journal_add_conjunction)(sd_journal *); // // sd_journal_add_conjunction = f; // return sd_journal_add_conjunction(j); // } // // void // my_sd_journal_flush_matches(void *f, sd_journal *j) // { // int (*sd_journal_flush_matches)(sd_journal *); // // sd_journal_flush_matches = f; // sd_journal_flush_matches(j); // } // // int // my_sd_journal_next(void *f, sd_journal *j) // { // int (*sd_journal_next)(sd_journal *); // // sd_journal_next = f; // return sd_journal_next(j); // } // // int // my_sd_journal_next_skip(void *f, sd_journal *j, uint64_t skip) // { // int (*sd_journal_next_skip)(sd_journal *, uint64_t); // // sd_journal_next_skip = f; // return sd_journal_next_skip(j, skip); // } // // int // my_sd_journal_previous(void *f, sd_journal *j) // { // int (*sd_journal_previous)(sd_journal *); // // sd_journal_previous = f; // return sd_journal_previous(j); // } // // int // my_sd_journal_previous_skip(void *f, sd_journal *j, uint64_t skip) // { // int (*sd_journal_previous_skip)(sd_journal *, uint64_t); // // sd_journal_previous_skip = f; // return sd_journal_previous_skip(j, skip); // } // // int // my_sd_journal_get_data(void *f, sd_journal *j, const char *field, const void **data, size_t *length) // { // int (*sd_journal_get_data)(sd_journal *, const char *, const void **, size_t *); // // sd_journal_get_data = f; // return sd_journal_get_data(j, field, data, length); // } // // int // my_sd_journal_set_data_threshold(void *f, sd_journal *j, size_t sz) // { // int (*sd_journal_set_data_threshold)(sd_journal *, size_t); // // sd_journal_set_data_threshold = f; // return sd_journal_set_data_threshold(j, sz); // } // // int // my_sd_journal_get_cursor(void *f, sd_journal *j, char **cursor) // { // int (*sd_journal_get_cursor)(sd_journal *, char **); // // sd_journal_get_cursor = f; // return sd_journal_get_cursor(j, cursor); // } // // int // my_sd_journal_test_cursor(void *f, sd_journal *j, const char *cursor) // { // int (*sd_journal_test_cursor)(sd_journal *, const char *); // // sd_journal_test_cursor = f; // return sd_journal_test_cursor(j, cursor); // } // // int // my_sd_journal_get_realtime_usec(void *f, sd_journal *j, uint64_t *usec) // { // int (*sd_journal_get_realtime_usec)(sd_journal *, uint64_t *); // // sd_journal_get_realtime_usec = f; // return sd_journal_get_realtime_usec(j, usec); // } // // int // my_sd_journal_get_monotonic_usec(void *f, sd_journal *j, uint64_t *usec, sd_id128_t *boot_id) // { // int (*sd_journal_get_monotonic_usec)(sd_journal *, uint64_t *, sd_id128_t *); // // sd_journal_get_monotonic_usec = f; // return sd_journal_get_monotonic_usec(j, usec, boot_id); // } // // int // my_sd_journal_seek_head(void *f, sd_journal *j) // { // int (*sd_journal_seek_head)(sd_journal *); // // sd_journal_seek_head = f; // return sd_journal_seek_head(j); // } // // int // my_sd_journal_seek_tail(void *f, sd_journal *j) // { // int (*sd_journal_seek_tail)(sd_journal *); // // sd_journal_seek_tail = f; // return sd_journal_seek_tail(j); // } // // // int // my_sd_journal_seek_cursor(void *f, sd_journal *j, const char *cursor) // { // int (*sd_journal_seek_cursor)(sd_journal *, const char *); // // sd_journal_seek_cursor = f; // return sd_journal_seek_cursor(j, cursor); // } // // int // my_sd_journal_seek_realtime_usec(void *f, sd_journal *j, uint64_t usec) // { // int (*sd_journal_seek_realtime_usec)(sd_journal *, uint64_t); // // sd_journal_seek_realtime_usec = f; // return sd_journal_seek_realtime_usec(j, usec); // } // // int // my_sd_journal_wait(void *f, sd_journal *j, uint64_t timeout_usec) // { // int (*sd_journal_wait)(sd_journal *, uint64_t); // // sd_journal_wait = f; // return sd_journal_wait(j, timeout_usec); // } // // void // my_sd_journal_restart_data(void *f, sd_journal *j) // { // void (*sd_journal_restart_data)(sd_journal *); // // sd_journal_restart_data = f; // sd_journal_restart_data(j); // } // // int // my_sd_journal_enumerate_data(void *f, sd_journal *j, const void **data, size_t *length) // { // int (*sd_journal_enumerate_data)(sd_journal *, const void **, size_t *); // // sd_journal_enumerate_data = f; // return sd_journal_enumerate_data(j, data, length); // } // import "C" import ( "bytes" "fmt" "strings" "sync" "syscall" "time" "unsafe" ) // Journal entry field strings which correspond to: // http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html const ( // User Journal Fields SD_JOURNAL_FIELD_MESSAGE = "MESSAGE" SD_JOURNAL_FIELD_MESSAGE_ID = "MESSAGE_ID" SD_JOURNAL_FIELD_PRIORITY = "PRIORITY" SD_JOURNAL_FIELD_CODE_FILE = "CODE_FILE" SD_JOURNAL_FIELD_CODE_LINE = "CODE_LINE" SD_JOURNAL_FIELD_CODE_FUNC = "CODE_FUNC" SD_JOURNAL_FIELD_ERRNO = "ERRNO" SD_JOURNAL_FIELD_SYSLOG_FACILITY = "SYSLOG_FACILITY" SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER = "SYSLOG_IDENTIFIER" SD_JOURNAL_FIELD_SYSLOG_PID = "SYSLOG_PID" // Trusted Journal Fields SD_JOURNAL_FIELD_PID = "_PID" SD_JOURNAL_FIELD_UID = "_UID" SD_JOURNAL_FIELD_GID = "_GID" SD_JOURNAL_FIELD_COMM = "_COMM" SD_JOURNAL_FIELD_EXE = "_EXE" SD_JOURNAL_FIELD_CMDLINE = "_CMDLINE" SD_JOURNAL_FIELD_CAP_EFFECTIVE = "_CAP_EFFECTIVE" SD_JOURNAL_FIELD_AUDIT_SESSION = "_AUDIT_SESSION" SD_JOURNAL_FIELD_AUDIT_LOGINUID = "_AUDIT_LOGINUID" SD_JOURNAL_FIELD_SYSTEMD_CGROUP = "_SYSTEMD_CGROUP" SD_JOURNAL_FIELD_SYSTEMD_SESSION = "_SYSTEMD_SESSION" SD_JOURNAL_FIELD_SYSTEMD_UNIT = "_SYSTEMD_UNIT" SD_JOURNAL_FIELD_SYSTEMD_USER_UNIT = "_SYSTEMD_USER_UNIT" SD_JOURNAL_FIELD_SYSTEMD_OWNER_UID = "_SYSTEMD_OWNER_UID" SD_JOURNAL_FIELD_SYSTEMD_SLICE = "_SYSTEMD_SLICE" SD_JOURNAL_FIELD_SELINUX_CONTEXT = "_SELINUX_CONTEXT" SD_JOURNAL_FIELD_SOURCE_REALTIME_TIMESTAMP = "_SOURCE_REALTIME_TIMESTAMP" SD_JOURNAL_FIELD_BOOT_ID = "_BOOT_ID" SD_JOURNAL_FIELD_MACHINE_ID = "_MACHINE_ID" SD_JOURNAL_FIELD_HOSTNAME = "_HOSTNAME" SD_JOURNAL_FIELD_TRANSPORT = "_TRANSPORT" // Address Fields SD_JOURNAL_FIELD_CURSOR = "__CURSOR" SD_JOURNAL_FIELD_REALTIME_TIMESTAMP = "__REALTIME_TIMESTAMP" SD_JOURNAL_FIELD_MONOTONIC_TIMESTAMP = "__MONOTONIC_TIMESTAMP" ) // Journal event constants const ( SD_JOURNAL_NOP = int(C.SD_JOURNAL_NOP) SD_JOURNAL_APPEND = int(C.SD_JOURNAL_APPEND) SD_JOURNAL_INVALIDATE = int(C.SD_JOURNAL_INVALIDATE) ) const ( // IndefiniteWait is a sentinel value that can be passed to // sdjournal.Wait() to signal an indefinite wait for new journal // events. It is implemented as the maximum value for a time.Duration: // https://github.com/golang/go/blob/e4dcf5c8c22d98ac9eac7b9b226596229624cb1d/src/time/time.go#L434 IndefiniteWait time.Duration = 1<<63 - 1 ) // Journal is a Go wrapper of an sd_journal structure. type Journal struct { cjournal *C.sd_journal mu sync.Mutex } // JournalEntry represents all fields of a journal entry plus address fields. type JournalEntry struct { Fields map[string]string Cursor string RealtimeTimestamp uint64 MonotonicTimestamp uint64 } // Match is a convenience wrapper to describe filters supplied to AddMatch. type Match struct { Field string Value string } // String returns a string representation of a Match suitable for use with AddMatch. func (m *Match) String() string { return m.Field + "=" + m.Value } // NewJournal returns a new Journal instance pointing to the local journal func NewJournal() (j *Journal, err error) { j = &Journal{} sd_journal_open, err := getFunction("sd_journal_open") if err != nil { return nil, err } r := C.my_sd_journal_open(sd_journal_open, &j.cjournal, C.SD_JOURNAL_LOCAL_ONLY) if r < 0 { return nil, fmt.Errorf("failed to open journal: %d", syscall.Errno(-r)) } return j, nil } // NewJournalFromDir returns a new Journal instance pointing to a journal residing // in a given directory. The supplied path may be relative or absolute; if // relative, it will be converted to an absolute path before being opened. func NewJournalFromDir(path string) (j *Journal, err error) { j = &Journal{} sd_journal_open_directory, err := getFunction("sd_journal_open_directory") if err != nil { return nil, err } p := C.CString(path) defer C.free(unsafe.Pointer(p)) r := C.my_sd_journal_open_directory(sd_journal_open_directory, &j.cjournal, p, 0) if r < 0 { return nil, fmt.Errorf("failed to open journal in directory %q: %d", path, syscall.Errno(-r)) } return j, nil } // Close closes a journal opened with NewJournal. func (j *Journal) Close() error { sd_journal_close, err := getFunction("sd_journal_close") if err != nil { return err } j.mu.Lock() C.my_sd_journal_close(sd_journal_close, j.cjournal) j.mu.Unlock() return nil } // AddMatch adds a match by which to filter the entries of the journal. func (j *Journal) AddMatch(match string) error { sd_journal_add_match, err := getFunction("sd_journal_add_match") if err != nil { return err } m := C.CString(match) defer C.free(unsafe.Pointer(m)) j.mu.Lock() r := C.my_sd_journal_add_match(sd_journal_add_match, j.cjournal, unsafe.Pointer(m), C.size_t(len(match))) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to add match: %d", syscall.Errno(-r)) } return nil } // AddDisjunction inserts a logical OR in the match list. func (j *Journal) AddDisjunction() error { sd_journal_add_disjunction, err := getFunction("sd_journal_add_disjunction") if err != nil { return err } j.mu.Lock() r := C.my_sd_journal_add_disjunction(sd_journal_add_disjunction, j.cjournal) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to add a disjunction in the match list: %d", syscall.Errno(-r)) } return nil } // AddConjunction inserts a logical AND in the match list. func (j *Journal) AddConjunction() error { sd_journal_add_conjunction, err := getFunction("sd_journal_add_conjunction") if err != nil { return err } j.mu.Lock() r := C.my_sd_journal_add_conjunction(sd_journal_add_conjunction, j.cjournal) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to add a conjunction in the match list: %d", syscall.Errno(-r)) } return nil } // FlushMatches flushes all matches, disjunctions and conjunctions. func (j *Journal) FlushMatches() { sd_journal_flush_matches, err := getFunction("sd_journal_flush_matches") if err != nil { return } j.mu.Lock() C.my_sd_journal_flush_matches(sd_journal_flush_matches, j.cjournal) j.mu.Unlock() } // Next advances the read pointer into the journal by one entry. func (j *Journal) Next() (int, error) { sd_journal_next, err := getFunction("sd_journal_next") if err != nil { return -1, err } j.mu.Lock() r := C.my_sd_journal_next(sd_journal_next, j.cjournal) j.mu.Unlock() if r < 0 { return int(r), fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r)) } return int(r), nil } // NextSkip advances the read pointer by multiple entries at once, // as specified by the skip parameter. func (j *Journal) NextSkip(skip uint64) (uint64, error) { sd_journal_next_skip, err := getFunction("sd_journal_next_skip") if err != nil { return 0, err } j.mu.Lock() r := C.my_sd_journal_next_skip(sd_journal_next_skip, j.cjournal, C.uint64_t(skip)) j.mu.Unlock() if r < 0 { return uint64(r), fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r)) } return uint64(r), nil } // Previous sets the read pointer into the journal back by one entry. func (j *Journal) Previous() (uint64, error) { sd_journal_previous, err := getFunction("sd_journal_previous") if err != nil { return 0, err } j.mu.Lock() r := C.my_sd_journal_previous(sd_journal_previous, j.cjournal) j.mu.Unlock() if r < 0 { return uint64(r), fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r)) } return uint64(r), nil } // PreviousSkip sets back the read pointer by multiple entries at once, // as specified by the skip parameter. func (j *Journal) PreviousSkip(skip uint64) (uint64, error) { sd_journal_previous_skip, err := getFunction("sd_journal_previous_skip") if err != nil { return 0, err } j.mu.Lock() r := C.my_sd_journal_previous_skip(sd_journal_previous_skip, j.cjournal, C.uint64_t(skip)) j.mu.Unlock() if r < 0 { return uint64(r), fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r)) } return uint64(r), nil } func (j *Journal) getData(field string) (unsafe.Pointer, C.int, error) { sd_journal_get_data, err := getFunction("sd_journal_get_data") if err != nil { return nil, 0, err } f := C.CString(field) defer C.free(unsafe.Pointer(f)) var d unsafe.Pointer var l C.size_t j.mu.Lock() r := C.my_sd_journal_get_data(sd_journal_get_data, j.cjournal, f, &d, &l) j.mu.Unlock() if r < 0 { return nil, 0, fmt.Errorf("failed to read message: %d", syscall.Errno(-r)) } return d, C.int(l), nil } // GetData gets the data object associated with a specific field from the // current journal entry. func (j *Journal) GetData(field string) (string, error) { d, l, err := j.getData(field) if err != nil { return "", err } return C.GoStringN((*C.char)(d), l), nil } // GetDataValue gets the data object associated with a specific field from the // current journal entry, returning only the value of the object. func (j *Journal) GetDataValue(field string) (string, error) { val, err := j.GetData(field) if err != nil { return "", err } return strings.SplitN(val, "=", 2)[1], nil } // GetDataBytes gets the data object associated with a specific field from the // current journal entry. func (j *Journal) GetDataBytes(field string) ([]byte, error) { d, l, err := j.getData(field) if err != nil { return nil, err } return C.GoBytes(d, l), nil } // GetDataValueBytes gets the data object associated with a specific field from the // current journal entry, returning only the value of the object. func (j *Journal) GetDataValueBytes(field string) ([]byte, error) { val, err := j.GetDataBytes(field) if err != nil { return nil, err } return bytes.SplitN(val, []byte("="), 2)[1], nil } // GetEntry returns a full representation of a journal entry with // all key-value pairs of data as well as address fields (cursor, realtime // timestamp and monotonic timestamp) func (j *Journal) GetEntry() (*JournalEntry, error) { sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec") if err != nil { return nil, err } sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec") if err != nil { return nil, err } sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor") if err != nil { return nil, err } sd_journal_restart_data, err := getFunction("sd_journal_restart_data") if err != nil { return nil, err } sd_journal_enumerate_data, err := getFunction("sd_journal_enumerate_data") if err != nil { return nil, err } j.mu.Lock() defer j.mu.Unlock() var r C.int entry := &JournalEntry{Fields: make(map[string]string)} var realtimeUsec C.uint64_t r = C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &realtimeUsec) if r < 0 { return nil, fmt.Errorf("failed to get realtime timestamp: %d", syscall.Errno(-r)) } entry.RealtimeTimestamp = uint64(realtimeUsec) var monotonicUsec C.uint64_t var boot_id C.sd_id128_t r = C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &monotonicUsec, &boot_id) if r < 0 { return nil, fmt.Errorf("failed to get monotonic timestamp: %d", syscall.Errno(-r)) } entry.MonotonicTimestamp = uint64(monotonicUsec) var c *C.char // since the pointer is mutated by sd_journal_get_cursor, need to wait // until after the call to free the memory r = C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &c) defer C.free(unsafe.Pointer(c)) if r < 0 { return nil, fmt.Errorf("failed to get cursor: %d", syscall.Errno(-r)) } entry.Cursor = C.GoString(c) // Implements the JOURNAL_FOREACH_DATA_RETVAL macro from journal-internal.h var d unsafe.Pointer var l C.size_t C.my_sd_journal_restart_data(sd_journal_restart_data, j.cjournal) for { r = C.my_sd_journal_enumerate_data(sd_journal_enumerate_data, j.cjournal, &d, &l) if r == 0 { break } if r < 0 { return nil, fmt.Errorf("failed to read message field: %d", syscall.Errno(-r)) } msg := C.GoStringN((*C.char)(d), C.int(l)) kv := strings.SplitN(msg, "=", 2) if len(kv) < 2 { return nil, fmt.Errorf("failed to parse field") } entry.Fields[kv[0]] = kv[1] } return entry, nil } // SetDataThresold sets the data field size threshold for data returned by // GetData. To retrieve the complete data fields this threshold should be // turned off by setting it to 0, so that the library always returns the // complete data objects. func (j *Journal) SetDataThreshold(threshold uint64) error { sd_journal_set_data_threshold, err := getFunction("sd_journal_set_data_threshold") if err != nil { return err } j.mu.Lock() r := C.my_sd_journal_set_data_threshold(sd_journal_set_data_threshold, j.cjournal, C.size_t(threshold)) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to set data threshold: %d", syscall.Errno(-r)) } return nil } // GetRealtimeUsec gets the realtime (wallclock) timestamp of the current // journal entry. func (j *Journal) GetRealtimeUsec() (uint64, error) { var usec C.uint64_t sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec") if err != nil { return 0, err } j.mu.Lock() r := C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &usec) j.mu.Unlock() if r < 0 { return 0, fmt.Errorf("failed to get realtime timestamp: %d", syscall.Errno(-r)) } return uint64(usec), nil } // GetMonotonicUsec gets the monotonic timestamp of the current journal entry. func (j *Journal) GetMonotonicUsec() (uint64, error) { var usec C.uint64_t var boot_id C.sd_id128_t sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec") if err != nil { return 0, err } j.mu.Lock() r := C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &usec, &boot_id) j.mu.Unlock() if r < 0 { return 0, fmt.Errorf("failed to get monotonic timestamp: %d", syscall.Errno(-r)) } return uint64(usec), nil } // GetCursor gets the cursor of the current journal entry. func (j *Journal) GetCursor() (string, error) { sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor") if err != nil { return "", err } var d *C.char // since the pointer is mutated by sd_journal_get_cursor, need to wait // until after the call to free the memory j.mu.Lock() r := C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &d) j.mu.Unlock() defer C.free(unsafe.Pointer(d)) if r < 0 { return "", fmt.Errorf("failed to get cursor: %d", syscall.Errno(-r)) } cursor := C.GoString(d) return cursor, nil } // TestCursor checks whether the current position in the journal matches the // specified cursor func (j *Journal) TestCursor(cursor string) error { sd_journal_test_cursor, err := getFunction("sd_journal_test_cursor") if err != nil { return err } c := C.CString(cursor) defer C.free(unsafe.Pointer(c)) j.mu.Lock() r := C.my_sd_journal_test_cursor(sd_journal_test_cursor, j.cjournal, c) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to test to cursor %q: %d", cursor, syscall.Errno(-r)) } return nil } // SeekHead seeks to the beginning of the journal, i.e. the oldest available // entry. func (j *Journal) SeekHead() error { sd_journal_seek_head, err := getFunction("sd_journal_seek_head") if err != nil { return err } j.mu.Lock() r := C.my_sd_journal_seek_head(sd_journal_seek_head, j.cjournal) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to seek to head of journal: %d", syscall.Errno(-r)) } return nil } // SeekTail may be used to seek to the end of the journal, i.e. the most recent // available entry. func (j *Journal) SeekTail() error { sd_journal_seek_tail, err := getFunction("sd_journal_seek_tail") if err != nil { return err } j.mu.Lock() r := C.my_sd_journal_seek_tail(sd_journal_seek_tail, j.cjournal) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to seek to tail of journal: %d", syscall.Errno(-r)) } return nil } // SeekRealtimeUsec seeks to the entry with the specified realtime (wallclock) // timestamp, i.e. CLOCK_REALTIME. func (j *Journal) SeekRealtimeUsec(usec uint64) error { sd_journal_seek_realtime_usec, err := getFunction("sd_journal_seek_realtime_usec") if err != nil { return err } j.mu.Lock() r := C.my_sd_journal_seek_realtime_usec(sd_journal_seek_realtime_usec, j.cjournal, C.uint64_t(usec)) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to seek to %d: %d", usec, syscall.Errno(-r)) } return nil } // SeekCursor seeks to a concrete journal cursor. func (j *Journal) SeekCursor(cursor string) error { sd_journal_seek_cursor, err := getFunction("sd_journal_seek_cursor") if err != nil { return err } c := C.CString(cursor) defer C.free(unsafe.Pointer(c)) j.mu.Lock() r := C.my_sd_journal_seek_cursor(sd_journal_seek_cursor, j.cjournal, c) j.mu.Unlock() if r < 0 { return fmt.Errorf("failed to seek to cursor %q: %d", cursor, syscall.Errno(-r)) } return nil } // Wait will synchronously wait until the journal gets changed. The maximum time // this call sleeps may be controlled with the timeout parameter. If // sdjournal.IndefiniteWait is passed as the timeout parameter, Wait will // wait indefinitely for a journal change. func (j *Journal) Wait(timeout time.Duration) int { var to uint64 sd_journal_wait, err := getFunction("sd_journal_wait") if err != nil { return -1 } if timeout == IndefiniteWait { // sd_journal_wait(3) calls for a (uint64_t) -1 to be passed to signify // indefinite wait, but using a -1 overflows our C.uint64_t, so we use an // equivalent hex value. to = 0xffffffffffffffff } else { to = uint64(time.Now().Add(timeout).Unix() / 1000) } j.mu.Lock() r := C.my_sd_journal_wait(sd_journal_wait, j.cjournal, C.uint64_t(to)) j.mu.Unlock() return int(r) } // GetUsage returns the journal disk space usage, in bytes. func (j *Journal) GetUsage() (uint64, error) { var out C.uint64_t sd_journal_get_usage, err := getFunction("sd_journal_get_usage") if err != nil { return 0, err } j.mu.Lock() r := C.my_sd_journal_get_usage(sd_journal_get_usage, j.cjournal, &out) j.mu.Unlock() if r < 0 { return 0, fmt.Errorf("failed to get journal disk space usage: %d", syscall.Errno(-r)) } return uint64(out), nil } ================================================ FILE: vendor/github.com/coreos/go-systemd/sdjournal/read.go ================================================ // Copyright 2015 RedHat, Inc. // Copyright 2015 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sdjournal import ( "errors" "fmt" "io" "log" "strings" "time" ) var ( ErrExpired = errors.New("Timeout expired") ) // JournalReaderConfig represents options to drive the behavior of a JournalReader. type JournalReaderConfig struct { // The Since, NumFromTail and Cursor options are mutually exclusive and // determine where the reading begins within the journal. The order in which // options are written is exactly the order of precedence. Since time.Duration // start relative to a Duration from now NumFromTail uint64 // start relative to the tail Cursor string // start relative to the cursor // Show only journal entries whose fields match the supplied values. If // the array is empty, entries will not be filtered. Matches []Match // If not empty, the journal instance will point to a journal residing // in this directory. The supplied path may be relative or absolute. Path string } // JournalReader is an io.ReadCloser which provides a simple interface for iterating through the // systemd journal. A JournalReader is not safe for concurrent use by multiple goroutines. type JournalReader struct { journal *Journal msgReader *strings.Reader } // NewJournalReader creates a new JournalReader with configuration options that are similar to the // systemd journalctl tool's iteration and filtering features. func NewJournalReader(config JournalReaderConfig) (*JournalReader, error) { r := &JournalReader{} // Open the journal var err error if config.Path != "" { r.journal, err = NewJournalFromDir(config.Path) } else { r.journal, err = NewJournal() } if err != nil { return nil, err } // Add any supplied matches for _, m := range config.Matches { r.journal.AddMatch(m.String()) } // Set the start position based on options if config.Since != 0 { // Start based on a relative time start := time.Now().Add(config.Since) if err := r.journal.SeekRealtimeUsec(uint64(start.UnixNano() / 1000)); err != nil { return nil, err } } else if config.NumFromTail != 0 { // Start based on a number of lines before the tail if err := r.journal.SeekTail(); err != nil { return nil, err } // Move the read pointer into position near the tail. Go one further than // the option so that the initial cursor advancement positions us at the // correct starting point. skip, err := r.journal.PreviousSkip(config.NumFromTail + 1) if err != nil { return nil, err } // If we skipped fewer lines than expected, we have reached journal start. // Thus, we seek to head so that next invocation can read the first line. if skip != config.NumFromTail+1 { if err := r.journal.SeekHead(); err != nil { return nil, err } } } else if config.Cursor != "" { // Start based on a custom cursor if err := r.journal.SeekCursor(config.Cursor); err != nil { return nil, err } } return r, nil } // Read reads entries from the journal. Read follows the Reader interface so // it must be able to read a specific amount of bytes. Journald on the other // hand only allows us to read full entries of arbitrary size (without byte // granularity). JournalReader is therefore internally buffering entries that // don't fit in the read buffer. Callers should keep calling until 0 and/or an // error is returned. func (r *JournalReader) Read(b []byte) (int, error) { var err error if r.msgReader == nil { var c int // Advance the journal cursor. It has to be called at least one time // before reading c, err = r.journal.Next() // An unexpected error if err != nil { return 0, err } // EOF detection if c == 0 { return 0, io.EOF } // Build a message var msg string msg, err = r.buildMessage() if err != nil { return 0, err } r.msgReader = strings.NewReader(msg) } // Copy and return the message var sz int sz, err = r.msgReader.Read(b) if err == io.EOF { // The current entry has been fully read. Don't propagate this // EOF, so the next entry can be read at the next Read() // iteration. r.msgReader = nil return sz, nil } if err != nil { return sz, err } if r.msgReader.Len() == 0 { r.msgReader = nil } return sz, nil } // Close closes the JournalReader's handle to the journal. func (r *JournalReader) Close() error { return r.journal.Close() } // Rewind attempts to rewind the JournalReader to the first entry. func (r *JournalReader) Rewind() error { r.msgReader = nil return r.journal.SeekHead() } // Follow synchronously follows the JournalReader, writing each new journal entry to writer. The // follow will continue until a single time.Time is received on the until channel. func (r *JournalReader) Follow(until <-chan time.Time, writer io.Writer) (err error) { // Process journal entries and events. Entries are flushed until the tail or // timeout is reached, and then we wait for new events or the timeout. var msg = make([]byte, 64*1<<(10)) process: for { c, err := r.Read(msg) if err != nil && err != io.EOF { break process } select { case <-until: return ErrExpired default: if c > 0 { if _, err = writer.Write(msg[:c]); err != nil { break process } continue process } } // We're at the tail, so wait for new events or time out. // Holds journal events to process. Tightly bounded for now unless there's a // reason to unblock the journal watch routine more quickly. events := make(chan int, 1) pollDone := make(chan bool, 1) go func() { for { select { case <-pollDone: return default: events <- r.journal.Wait(time.Duration(1) * time.Second) } } }() select { case <-until: pollDone <- true return ErrExpired case e := <-events: pollDone <- true switch e { case SD_JOURNAL_NOP, SD_JOURNAL_APPEND, SD_JOURNAL_INVALIDATE: // TODO: need to account for any of these? default: log.Printf("Received unknown event: %d\n", e) } continue process } } return } // buildMessage returns a string representing the current journal entry in a simple format which // includes the entry timestamp and MESSAGE field. func (r *JournalReader) buildMessage() (string, error) { var msg string var usec uint64 var err error if msg, err = r.journal.GetData("MESSAGE"); err != nil { return "", err } if usec, err = r.journal.GetRealtimeUsec(); err != nil { return "", err } timestamp := time.Unix(0, int64(usec)*int64(time.Microsecond)) return fmt.Sprintf("%s %s\n", timestamp, msg), nil } ================================================ FILE: vendor/github.com/coreos/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/coreos/pkg/NOTICE ================================================ CoreOS Project Copyright 2014 CoreOS, Inc This product includes software developed at CoreOS, Inc. (http://www.coreos.com/). ================================================ FILE: vendor/github.com/coreos/pkg/dlopen/dlopen.go ================================================ // Copyright 2016 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package dlopen provides some convenience functions to dlopen a library and // get its symbols. package dlopen // #cgo LDFLAGS: -ldl // #include // #include import "C" import ( "errors" "fmt" "unsafe" ) var ErrSoNotFound = errors.New("unable to open a handle to the library") // LibHandle represents an open handle to a library (.so) type LibHandle struct { Handle unsafe.Pointer Libname string } // GetHandle tries to get a handle to a library (.so), attempting to access it // by the names specified in libs and returning the first that is successfully // opened. Callers are responsible for closing the handler. If no library can // be successfully opened, an error is returned. func GetHandle(libs []string) (*LibHandle, error) { for _, name := range libs { libname := C.CString(name) defer C.free(unsafe.Pointer(libname)) handle := C.dlopen(libname, C.RTLD_LAZY) if handle != nil { h := &LibHandle{ Handle: handle, Libname: name, } return h, nil } } return nil, ErrSoNotFound } // GetSymbolPointer takes a symbol name and returns a pointer to the symbol. func (l *LibHandle) GetSymbolPointer(symbol string) (unsafe.Pointer, error) { sym := C.CString(symbol) defer C.free(unsafe.Pointer(sym)) C.dlerror() p := C.dlsym(l.Handle, sym) e := C.dlerror() if e != nil { return nil, fmt.Errorf("error resolving symbol %q: %v", symbol, errors.New(C.GoString(e))) } return p, nil } // Close closes a LibHandle. func (l *LibHandle) Close() error { C.dlerror() C.dlclose(l.Handle) e := C.dlerror() if e != nil { return fmt.Errorf("error closing %v: %v", l.Libname, errors.New(C.GoString(e))) } return nil } ================================================ FILE: vendor/github.com/coreos/pkg/dlopen/dlopen_example.go ================================================ // Copyright 2015 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // +build linux package dlopen // #include // #include // // int // my_strlen(void *f, const char *s) // { // size_t (*strlen)(const char *); // // strlen = (size_t (*)(const char *))f; // return strlen(s); // } import "C" import ( "fmt" "unsafe" ) func strlen(libs []string, s string) (int, error) { h, err := GetHandle(libs) if err != nil { return -1, fmt.Errorf(`couldn't get a handle to the library: %v`, err) } defer h.Close() f := "strlen" cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) strlen, err := h.GetSymbolPointer(f) if err != nil { return -1, fmt.Errorf(`couldn't get symbol %q: %v`, f, err) } len := C.my_strlen(strlen, cs) return int(len), nil } ================================================ FILE: vendor/github.com/go-ini/ini/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/go-ini/ini/Makefile ================================================ .PHONY: build test bench vet build: vet bench test: go test -v -cover -race bench: go test -v -cover -race -test.bench=. -test.benchmem vet: go vet ================================================ FILE: vendor/github.com/go-ini/ini/README.md ================================================ INI [![Build Status](https://travis-ci.org/go-ini/ini.svg?branch=master)](https://travis-ci.org/go-ini/ini) === ![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) Package ini provides INI file read and write functionality in Go. [简体中文](README_ZH.md) ## Feature - Load multiple data sources(`[]byte` or file) with overwrites. - Read with recursion values. - Read with parent-child sections. - Read with auto-increment key names. - Read with multiple-line values. - Read with tons of helper methods. - Read and convert values to Go types. - Read and **WRITE** comments of sections and keys. - Manipulate sections, keys and comments with ease. - Keep sections and keys in order as you parse and save. ## Installation To use a tagged revision: go get gopkg.in/ini.v1 To use with latest changes: go get github.com/go-ini/ini Please add `-u` flag to update in the future. ### Testing If you want to test on your machine, please apply `-t` flag: go get -t gopkg.in/ini.v1 Please add `-u` flag to update in the future. ## Getting Started ### Loading from data sources A **Data Source** is either raw data in type `[]byte` or a file name with type `string` and you can load **as many data sources as you want**. Passing other types will simply return an error. ```go cfg, err := ini.Load([]byte("raw data"), "filename") ``` Or start with an empty object: ```go cfg := ini.Empty() ``` When you cannot decide how many data sources to load at the beginning, you will still be able to **Append()** them later. ```go err := cfg.Append("other file", []byte("other raw data")) ``` If you have a list of files with possibilities that some of them may not available at the time, and you don't know exactly which ones, you can use `LooseLoad` to ignore nonexistent files without returning error. ```go cfg, err := ini.LooseLoad("filename", "filename_404") ``` The cool thing is, whenever the file is available to load while you're calling `Reload` method, it will be counted as usual. #### Ignore cases of key name When you do not care about cases of section and key names, you can use `InsensitiveLoad` to force all names to be lowercased while parsing. ```go cfg, err := ini.InsensitiveLoad("filename") //... // sec1 and sec2 are the exactly same section object sec1, err := cfg.GetSection("Section") sec2, err := cfg.GetSection("SecTIOn") // key1 and key2 are the exactly same key object key1, err := cfg.GetKey("Key") key2, err := cfg.GetKey("KeY") ``` #### MySQL-like boolean key MySQL's configuration allows a key without value as follows: ```ini [mysqld] ... skip-host-cache skip-name-resolve ``` By default, this is considered as missing value. But if you know you're going to deal with those cases, you can assign advanced load options: ```go cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf")) ``` The value of those keys are always `true`, and when you save to a file, it will keep in the same foramt as you read. ### Working with sections To get a section, you would need to: ```go section, err := cfg.GetSection("section name") ``` For a shortcut for default section, just give an empty string as name: ```go section, err := cfg.GetSection("") ``` When you're pretty sure the section exists, following code could make your life easier: ```go section := cfg.Section("") ``` What happens when the section somehow does not exist? Don't panic, it automatically creates and returns a new section to you. To create a new section: ```go err := cfg.NewSection("new section") ``` To get a list of sections or section names: ```go sections := cfg.Sections() names := cfg.SectionStrings() ``` ### Working with keys To get a key under a section: ```go key, err := cfg.Section("").GetKey("key name") ``` Same rule applies to key operations: ```go key := cfg.Section("").Key("key name") ``` To check if a key exists: ```go yes := cfg.Section("").HasKey("key name") ``` To create a new key: ```go err := cfg.Section("").NewKey("name", "value") ``` To get a list of keys or key names: ```go keys := cfg.Section("").Keys() names := cfg.Section("").KeyStrings() ``` To get a clone hash of keys and corresponding values: ```go hash := cfg.Section("").KeysHash() ``` ### Working with values To get a string value: ```go val := cfg.Section("").Key("key name").String() ``` To validate key value on the fly: ```go val := cfg.Section("").Key("key name").Validate(func(in string) string { if len(in) == 0 { return "default" } return in }) ``` If you do not want any auto-transformation (such as recursive read) for the values, you can get raw value directly (this way you get much better performance): ```go val := cfg.Section("").Key("key name").Value() ``` To check if raw value exists: ```go yes := cfg.Section("").HasValue("test value") ``` To get value with types: ```go // For boolean values: // true when value is: 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On // false when value is: 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off v, err = cfg.Section("").Key("BOOL").Bool() v, err = cfg.Section("").Key("FLOAT64").Float64() v, err = cfg.Section("").Key("INT").Int() v, err = cfg.Section("").Key("INT64").Int64() v, err = cfg.Section("").Key("UINT").Uint() v, err = cfg.Section("").Key("UINT64").Uint64() v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339) v, err = cfg.Section("").Key("TIME").Time() // RFC3339 v = cfg.Section("").Key("BOOL").MustBool() v = cfg.Section("").Key("FLOAT64").MustFloat64() v = cfg.Section("").Key("INT").MustInt() v = cfg.Section("").Key("INT64").MustInt64() v = cfg.Section("").Key("UINT").MustUint() v = cfg.Section("").Key("UINT64").MustUint64() v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339) v = cfg.Section("").Key("TIME").MustTime() // RFC3339 // Methods start with Must also accept one argument for default value // when key not found or fail to parse value to given type. // Except method MustString, which you have to pass a default value. v = cfg.Section("").Key("String").MustString("default") v = cfg.Section("").Key("BOOL").MustBool(true) v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25) v = cfg.Section("").Key("INT").MustInt(10) v = cfg.Section("").Key("INT64").MustInt64(99) v = cfg.Section("").Key("UINT").MustUint(3) v = cfg.Section("").Key("UINT64").MustUint64(6) v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now()) v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339 ``` What if my value is three-line long? ```ini [advance] ADDRESS = """404 road, NotFound, State, 5000 Earth""" ``` Not a problem! ```go cfg.Section("advance").Key("ADDRESS").String() /* --- start --- 404 road, NotFound, State, 5000 Earth ------ end --- */ ``` That's cool, how about continuation lines? ```ini [advance] two_lines = how about \ continuation lines? lots_of_lines = 1 \ 2 \ 3 \ 4 ``` Piece of cake! ```go cfg.Section("advance").Key("two_lines").String() // how about continuation lines? cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4 ``` Well, I hate continuation lines, how do I disable that? ```go cfg, err := ini.LoadSources(ini.LoadOptions{ IgnoreContinuation: true, }, "filename") ``` Holy crap! Note that single quotes around values will be stripped: ```ini foo = "some value" // foo: some value bar = 'some value' // bar: some value ``` That's all? Hmm, no. #### Helper methods of working with values To get value with given candidates: ```go v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"}) v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75}) v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30}) v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30}) v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9}) v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9}) v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3}) v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339 ``` Default value will be presented if value of key is not in candidates you given, and default value does not need be one of candidates. To validate value in a given range: ```go vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2) vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20) vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20) vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9) vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9) vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime) vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339 ``` ##### Auto-split values into a slice To use zero value of type for invalid inputs: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0] vals = cfg.Section("").Key("STRINGS").Strings(",") vals = cfg.Section("").Key("FLOAT64S").Float64s(",") vals = cfg.Section("").Key("INTS").Ints(",") vals = cfg.Section("").Key("INT64S").Int64s(",") vals = cfg.Section("").Key("UINTS").Uints(",") vals = cfg.Section("").Key("UINT64S").Uint64s(",") vals = cfg.Section("").Key("TIMES").Times(",") ``` To exclude invalid values out of result slice: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> [2.2] vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",") vals = cfg.Section("").Key("INTS").ValidInts(",") vals = cfg.Section("").Key("INT64S").ValidInt64s(",") vals = cfg.Section("").Key("UINTS").ValidUints(",") vals = cfg.Section("").Key("UINT64S").ValidUint64s(",") vals = cfg.Section("").Key("TIMES").ValidTimes(",") ``` Or to return nothing but error when have invalid inputs: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> error vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",") vals = cfg.Section("").Key("INTS").StrictInts(",") vals = cfg.Section("").Key("INT64S").StrictInt64s(",") vals = cfg.Section("").Key("UINTS").StrictUints(",") vals = cfg.Section("").Key("UINT64S").StrictUint64s(",") vals = cfg.Section("").Key("TIMES").StrictTimes(",") ``` ### Save your configuration Finally, it's time to save your configuration to somewhere. A typical way to save configuration is writing it to a file: ```go // ... err = cfg.SaveTo("my.ini") err = cfg.SaveToIndent("my.ini", "\t") ``` Another way to save is writing to a `io.Writer` interface: ```go // ... cfg.WriteTo(writer) cfg.WriteToIndent(writer, "\t") ``` ## Advanced Usage ### Recursive Values For all value of keys, there is a special syntax `%()s`, where `` is the key name in same section or default section, and `%()s` will be replaced by corresponding value(empty string if key not found). You can use this syntax at most 99 level of recursions. ```ini NAME = ini [author] NAME = Unknwon GITHUB = https://github.com/%(NAME)s [package] FULL_NAME = github.com/go-ini/%(NAME)s ``` ```go cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini ``` ### Parent-child Sections You can use `.` in section name to indicate parent-child relationship between two or more sections. If the key not found in the child section, library will try again on its parent section until there is no parent section. ```ini NAME = ini VERSION = v1 IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s [package] CLONE_URL = https://%(IMPORT_PATH)s [package.sub] ``` ```go cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1 ``` #### Retrieve parent keys available to a child section ```go cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"] ``` ### Auto-increment Key Names If key name is `-` in data source, then it would be seen as special syntax for auto-increment key name start from 1, and every section is independent on counter. ```ini [features] -: Support read/write comments of keys and sections -: Support auto-increment of key names -: Support load multiple files to overwrite key values ``` ```go cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"} ``` ### Map To Struct Want more objective way to play with INI? Cool. ```ini Name = Unknwon age = 21 Male = true Born = 1993-01-01T20:17:05Z [Note] Content = Hi is a good man! Cities = HangZhou, Boston ``` ```go type Note struct { Content string Cities []string } type Person struct { Name string Age int `ini:"age"` Male bool Born time.Time Note Created time.Time `ini:"-"` } func main() { cfg, err := ini.Load("path/to/ini") // ... p := new(Person) err = cfg.MapTo(p) // ... // Things can be simpler. err = ini.MapTo(p, "path/to/ini") // ... // Just map a section? Fine. n := new(Note) err = cfg.Section("Note").MapTo(n) // ... } ``` Can I have default value for field? Absolutely. Assign it before you map to struct. It will keep the value as it is if the key is not presented or got wrong type. ```go // ... p := &Person{ Name: "Joe", } // ... ``` It's really cool, but what's the point if you can't give me my file back from struct? ### Reflect From Struct Why not? ```go type Embeded struct { Dates []time.Time `delim:"|"` Places []string `ini:"places,omitempty"` None []int `ini:",omitempty"` } type Author struct { Name string `ini:"NAME"` Male bool Age int GPA float64 NeverMind string `ini:"-"` *Embeded } func main() { a := &Author{"Unknwon", true, 21, 2.8, "", &Embeded{ []time.Time{time.Now(), time.Now()}, []string{"HangZhou", "Boston"}, []int{}, }} cfg := ini.Empty() err = ini.ReflectFrom(cfg, a) // ... } ``` So, what do I get? ```ini NAME = Unknwon Male = true Age = 21 GPA = 2.8 [Embeded] Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00 places = HangZhou,Boston ``` #### Name Mapper To save your time and make your code cleaner, this library supports [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) between struct field and actual section and key name. There are 2 built-in name mappers: - `AllCapsUnderscore`: it converts to format `ALL_CAPS_UNDERSCORE` then match section or key. - `TitleUnderscore`: it converts to format `title_underscore` then match section or key. To use them: ```go type Info struct { PackageName string } func main() { err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini")) // ... cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) // ... info := new(Info) cfg.NameMapper = ini.AllCapsUnderscore err = cfg.MapTo(info) // ... } ``` Same rules of name mapper apply to `ini.ReflectFromWithMapper` function. #### Value Mapper To expand values (e.g. from environment variables), you can use the `ValueMapper` to transform values: ```go type Env struct { Foo string `ini:"foo"` } func main() { cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n") cfg.ValueMapper = os.ExpandEnv // ... env := &Env{} err = cfg.Section("env").MapTo(env) } ``` This would set the value of `env.Foo` to the value of the environment variable `MY_VAR`. #### Other Notes On Map/Reflect Any embedded struct is treated as a section by default, and there is no automatic parent-child relations in map/reflect feature: ```go type Child struct { Age string } type Parent struct { Name string Child } type Config struct { City string Parent } ``` Example configuration: ```ini City = Boston [Parent] Name = Unknwon [Child] Age = 21 ``` What if, yes, I'm paranoid, I want embedded struct to be in the same section. Well, all roads lead to Rome. ```go type Child struct { Age string } type Parent struct { Name string Child `ini:"Parent"` } type Config struct { City string Parent } ``` Example configuration: ```ini City = Boston [Parent] Name = Unknwon Age = 21 ``` ## Getting Help - [API Documentation](https://gowalker.org/gopkg.in/ini.v1) - [File An Issue](https://github.com/go-ini/ini/issues/new) ## FAQs ### What does `BlockMode` field do? By default, library lets you read and write values so we need a locker to make sure your data is safe. But in cases that you are very sure about only reading data through the library, you can set `cfg.BlockMode = false` to speed up read operations about **50-70%** faster. ### Why another INI library? Many people are using my another INI library [goconfig](https://github.com/Unknwon/goconfig), so the reason for this one is I would like to make more Go style code. Also when you set `cfg.BlockMode = false`, this one is about **10-30%** faster. To make those changes I have to confirm API broken, so it's safer to keep it in another place and start using `gopkg.in` to version my package at this time.(PS: shorter import path) ## License This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text. ================================================ FILE: vendor/github.com/go-ini/ini/README_ZH.md ================================================ 本包提供了 Go 语言中读写 INI 文件的功能。 ## 功能特性 - 支持覆盖加载多个数据源(`[]byte` 或文件) - 支持递归读取键值 - 支持读取父子分区 - 支持读取自增键名 - 支持读取多行的键值 - 支持大量辅助方法 - 支持在读取时直接转换为 Go 语言类型 - 支持读取和 **写入** 分区和键的注释 - 轻松操作分区、键值和注释 - 在保存文件时分区和键值会保持原有的顺序 ## 下载安装 使用一个特定版本: go get gopkg.in/ini.v1 使用最新版: go get github.com/go-ini/ini 如需更新请添加 `-u` 选项。 ### 测试安装 如果您想要在自己的机器上运行测试,请使用 `-t` 标记: go get -t gopkg.in/ini.v1 如需更新请添加 `-u` 选项。 ## 开始使用 ### 从数据源加载 一个 **数据源** 可以是 `[]byte` 类型的原始数据,或 `string` 类型的文件路径。您可以加载 **任意多个** 数据源。如果您传递其它类型的数据源,则会直接返回错误。 ```go cfg, err := ini.Load([]byte("raw data"), "filename") ``` 或者从一个空白的文件开始: ```go cfg := ini.Empty() ``` 当您在一开始无法决定需要加载哪些数据源时,仍可以使用 **Append()** 在需要的时候加载它们。 ```go err := cfg.Append("other file", []byte("other raw data")) ``` 当您想要加载一系列文件,但是不能够确定其中哪些文件是不存在的,可以通过调用函数 `LooseLoad` 来忽略它们(`Load` 会因为文件不存在而返回错误): ```go cfg, err := ini.LooseLoad("filename", "filename_404") ``` 更牛逼的是,当那些之前不存在的文件在重新调用 `Reload` 方法的时候突然出现了,那么它们会被正常加载。 #### 忽略键名的大小写 有时候分区和键的名称大小写混合非常烦人,这个时候就可以通过 `InsensitiveLoad` 将所有分区和键名在读取里强制转换为小写: ```go cfg, err := ini.InsensitiveLoad("filename") //... // sec1 和 sec2 指向同一个分区对象 sec1, err := cfg.GetSection("Section") sec2, err := cfg.GetSection("SecTIOn") // key1 和 key2 指向同一个键对象 key1, err := cfg.GetKey("Key") key2, err := cfg.GetKey("KeY") ``` #### 类似 MySQL 配置中的布尔值键 MySQL 的配置文件中会出现没有具体值的布尔类型的键: ```ini [mysqld] ... skip-host-cache skip-name-resolve ``` 默认情况下这被认为是缺失值而无法完成解析,但可以通过高级的加载选项对它们进行处理: ```go cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf")) ``` 这些键的值永远为 `true`,且在保存到文件时也只会输出键名。 ### 操作分区(Section) 获取指定分区: ```go section, err := cfg.GetSection("section name") ``` 如果您想要获取默认分区,则可以用空字符串代替分区名: ```go section, err := cfg.GetSection("") ``` 当您非常确定某个分区是存在的,可以使用以下简便方法: ```go section := cfg.Section("") ``` 如果不小心判断错了,要获取的分区其实是不存在的,那会发生什么呢?没事的,它会自动创建并返回一个对应的分区对象给您。 创建一个分区: ```go err := cfg.NewSection("new section") ``` 获取所有分区对象或名称: ```go sections := cfg.Sections() names := cfg.SectionStrings() ``` ### 操作键(Key) 获取某个分区下的键: ```go key, err := cfg.Section("").GetKey("key name") ``` 和分区一样,您也可以直接获取键而忽略错误处理: ```go key := cfg.Section("").Key("key name") ``` 判断某个键是否存在: ```go yes := cfg.Section("").HasKey("key name") ``` 创建一个新的键: ```go err := cfg.Section("").NewKey("name", "value") ``` 获取分区下的所有键或键名: ```go keys := cfg.Section("").Keys() names := cfg.Section("").KeyStrings() ``` 获取分区下的所有键值对的克隆: ```go hash := cfg.Section("").KeysHash() ``` ### 操作键值(Value) 获取一个类型为字符串(string)的值: ```go val := cfg.Section("").Key("key name").String() ``` 获取值的同时通过自定义函数进行处理验证: ```go val := cfg.Section("").Key("key name").Validate(func(in string) string { if len(in) == 0 { return "default" } return in }) ``` 如果您不需要任何对值的自动转变功能(例如递归读取),可以直接获取原值(这种方式性能最佳): ```go val := cfg.Section("").Key("key name").Value() ``` 判断某个原值是否存在: ```go yes := cfg.Section("").HasValue("test value") ``` 获取其它类型的值: ```go // 布尔值的规则: // true 当值为:1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On // false 当值为:0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off v, err = cfg.Section("").Key("BOOL").Bool() v, err = cfg.Section("").Key("FLOAT64").Float64() v, err = cfg.Section("").Key("INT").Int() v, err = cfg.Section("").Key("INT64").Int64() v, err = cfg.Section("").Key("UINT").Uint() v, err = cfg.Section("").Key("UINT64").Uint64() v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339) v, err = cfg.Section("").Key("TIME").Time() // RFC3339 v = cfg.Section("").Key("BOOL").MustBool() v = cfg.Section("").Key("FLOAT64").MustFloat64() v = cfg.Section("").Key("INT").MustInt() v = cfg.Section("").Key("INT64").MustInt64() v = cfg.Section("").Key("UINT").MustUint() v = cfg.Section("").Key("UINT64").MustUint64() v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339) v = cfg.Section("").Key("TIME").MustTime() // RFC3339 // 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值, // 当键不存在或者转换失败时,则会直接返回该默认值。 // 但是,MustString 方法必须传递一个默认值。 v = cfg.Seciont("").Key("String").MustString("default") v = cfg.Section("").Key("BOOL").MustBool(true) v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25) v = cfg.Section("").Key("INT").MustInt(10) v = cfg.Section("").Key("INT64").MustInt64(99) v = cfg.Section("").Key("UINT").MustUint(3) v = cfg.Section("").Key("UINT64").MustUint64(6) v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now()) v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339 ``` 如果我的值有好多行怎么办? ```ini [advance] ADDRESS = """404 road, NotFound, State, 5000 Earth""" ``` 嗯哼?小 case! ```go cfg.Section("advance").Key("ADDRESS").String() /* --- start --- 404 road, NotFound, State, 5000 Earth ------ end --- */ ``` 赞爆了!那要是我属于一行的内容写不下想要写到第二行怎么办? ```ini [advance] two_lines = how about \ continuation lines? lots_of_lines = 1 \ 2 \ 3 \ 4 ``` 简直是小菜一碟! ```go cfg.Section("advance").Key("two_lines").String() // how about continuation lines? cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4 ``` 可是我有时候觉得两行连在一起特别没劲,怎么才能不自动连接两行呢? ```go cfg, err := ini.LoadSources(ini.LoadOptions{ IgnoreContinuation: true, }, "filename") ``` 哇靠给力啊! 需要注意的是,值两侧的单引号会被自动剔除: ```ini foo = "some value" // foo: some value bar = 'some value' // bar: some value ``` 这就是全部了?哈哈,当然不是。 #### 操作键值的辅助方法 获取键值时设定候选值: ```go v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"}) v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75}) v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30}) v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30}) v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9}) v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9}) v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3}) v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339 ``` 如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。 验证获取的值是否在指定范围内: ```go vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2) vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20) vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20) vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9) vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9) vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime) vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339 ``` ##### 自动分割键值到切片(slice) 当存在无效输入时,使用零值代替: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0] vals = cfg.Section("").Key("STRINGS").Strings(",") vals = cfg.Section("").Key("FLOAT64S").Float64s(",") vals = cfg.Section("").Key("INTS").Ints(",") vals = cfg.Section("").Key("INT64S").Int64s(",") vals = cfg.Section("").Key("UINTS").Uints(",") vals = cfg.Section("").Key("UINT64S").Uint64s(",") vals = cfg.Section("").Key("TIMES").Times(",") ``` 从结果切片中剔除无效输入: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> [2.2] vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",") vals = cfg.Section("").Key("INTS").ValidInts(",") vals = cfg.Section("").Key("INT64S").ValidInt64s(",") vals = cfg.Section("").Key("UINTS").ValidUints(",") vals = cfg.Section("").Key("UINT64S").ValidUint64s(",") vals = cfg.Section("").Key("TIMES").ValidTimes(",") ``` 当存在无效输入时,直接返回错误: ```go // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4] // Input: how, 2.2, are, you -> error vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",") vals = cfg.Section("").Key("INTS").StrictInts(",") vals = cfg.Section("").Key("INT64S").StrictInt64s(",") vals = cfg.Section("").Key("UINTS").StrictUints(",") vals = cfg.Section("").Key("UINT64S").StrictUint64s(",") vals = cfg.Section("").Key("TIMES").StrictTimes(",") ``` ### 保存配置 终于到了这个时刻,是时候保存一下配置了。 比较原始的做法是输出配置到某个文件: ```go // ... err = cfg.SaveTo("my.ini") err = cfg.SaveToIndent("my.ini", "\t") ``` 另一个比较高级的做法是写入到任何实现 `io.Writer` 接口的对象中: ```go // ... cfg.WriteTo(writer) cfg.WriteToIndent(writer, "\t") ``` ### 高级用法 #### 递归读取键值 在获取所有键值的过程中,特殊语法 `%()s` 会被应用,其中 `` 可以是相同分区或者默认分区下的键名。字符串 `%()s` 会被相应的键值所替代,如果指定的键不存在,则会用空字符串替代。您可以最多使用 99 层的递归嵌套。 ```ini NAME = ini [author] NAME = Unknwon GITHUB = https://github.com/%(NAME)s [package] FULL_NAME = github.com/go-ini/%(NAME)s ``` ```go cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini ``` #### 读取父子分区 您可以在分区名称中使用 `.` 来表示两个或多个分区之间的父子关系。如果某个键在子分区中不存在,则会去它的父分区中再次寻找,直到没有父分区为止。 ```ini NAME = ini VERSION = v1 IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s [package] CLONE_URL = https://%(IMPORT_PATH)s [package.sub] ``` ```go cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1 ``` #### 获取上级父分区下的所有键名 ```go cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"] ``` #### 读取自增键名 如果数据源中的键名为 `-`,则认为该键使用了自增键名的特殊语法。计数器从 1 开始,并且分区之间是相互独立的。 ```ini [features] -: Support read/write comments of keys and sections -: Support auto-increment of key names -: Support load multiple files to overwrite key values ``` ```go cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"} ``` ### 映射到结构 想要使用更加面向对象的方式玩转 INI 吗?好主意。 ```ini Name = Unknwon age = 21 Male = true Born = 1993-01-01T20:17:05Z [Note] Content = Hi is a good man! Cities = HangZhou, Boston ``` ```go type Note struct { Content string Cities []string } type Person struct { Name string Age int `ini:"age"` Male bool Born time.Time Note Created time.Time `ini:"-"` } func main() { cfg, err := ini.Load("path/to/ini") // ... p := new(Person) err = cfg.MapTo(p) // ... // 一切竟可以如此的简单。 err = ini.MapTo(p, "path/to/ini") // ... // 嗯哼?只需要映射一个分区吗? n := new(Note) err = cfg.Section("Note").MapTo(n) // ... } ``` 结构的字段怎么设置默认值呢?很简单,只要在映射之前对指定字段进行赋值就可以了。如果键未找到或者类型错误,该值不会发生改变。 ```go // ... p := &Person{ Name: "Joe", } // ... ``` 这样玩 INI 真的好酷啊!然而,如果不能还给我原来的配置文件,有什么卵用? ### 从结构反射 可是,我有说不能吗? ```go type Embeded struct { Dates []time.Time `delim:"|"` Places []string `ini:"places,omitempty"` None []int `ini:",omitempty"` } type Author struct { Name string `ini:"NAME"` Male bool Age int GPA float64 NeverMind string `ini:"-"` *Embeded } func main() { a := &Author{"Unknwon", true, 21, 2.8, "", &Embeded{ []time.Time{time.Now(), time.Now()}, []string{"HangZhou", "Boston"}, []int{}, }} cfg := ini.Empty() err = ini.ReflectFrom(cfg, a) // ... } ``` 瞧瞧,奇迹发生了。 ```ini NAME = Unknwon Male = true Age = 21 GPA = 2.8 [Embeded] Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00 places = HangZhou,Boston ``` #### 名称映射器(Name Mapper) 为了节省您的时间并简化代码,本库支持类型为 [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) 的名称映射器,该映射器负责结构字段名与分区名和键名之间的映射。 目前有 2 款内置的映射器: - `AllCapsUnderscore`:该映射器将字段名转换至格式 `ALL_CAPS_UNDERSCORE` 后再去匹配分区名和键名。 - `TitleUnderscore`:该映射器将字段名转换至格式 `title_underscore` 后再去匹配分区名和键名。 使用方法: ```go type Info struct{ PackageName string } func main() { err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("package_name=ini")) // ... cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) // ... info := new(Info) cfg.NameMapper = ini.AllCapsUnderscore err = cfg.MapTo(info) // ... } ``` 使用函数 `ini.ReflectFromWithMapper` 时也可应用相同的规则。 #### 值映射器(Value Mapper) 值映射器允许使用一个自定义函数自动展开值的具体内容,例如:运行时获取环境变量: ```go type Env struct { Foo string `ini:"foo"` } func main() { cfg, err := ini.Load([]byte("[env]\nfoo = ${MY_VAR}\n") cfg.ValueMapper = os.ExpandEnv // ... env := &Env{} err = cfg.Section("env").MapTo(env) } ``` 本例中,`env.Foo` 将会是运行时所获取到环境变量 `MY_VAR` 的值。 #### 映射/反射的其它说明 任何嵌入的结构都会被默认认作一个不同的分区,并且不会自动产生所谓的父子分区关联: ```go type Child struct { Age string } type Parent struct { Name string Child } type Config struct { City string Parent } ``` 示例配置文件: ```ini City = Boston [Parent] Name = Unknwon [Child] Age = 21 ``` 很好,但是,我就是要嵌入结构也在同一个分区。好吧,你爹是李刚! ```go type Child struct { Age string } type Parent struct { Name string Child `ini:"Parent"` } type Config struct { City string Parent } ``` 示例配置文件: ```ini City = Boston [Parent] Name = Unknwon Age = 21 ``` ## 获取帮助 - [API 文档](https://gowalker.org/gopkg.in/ini.v1) - [创建工单](https://github.com/go-ini/ini/issues/new) ## 常见问题 ### 字段 `BlockMode` 是什么? 默认情况下,本库会在您进行读写操作时采用锁机制来确保数据时间。但在某些情况下,您非常确定只进行读操作。此时,您可以通过设置 `cfg.BlockMode = false` 来将读操作提升大约 **50-70%** 的性能。 ### 为什么要写另一个 INI 解析库? 许多人都在使用我的 [goconfig](https://github.com/Unknwon/goconfig) 来完成对 INI 文件的操作,但我希望使用更加 Go 风格的代码。并且当您设置 `cfg.BlockMode = false` 时,会有大约 **10-30%** 的性能提升。 为了做出这些改变,我必须对 API 进行破坏,所以新开一个仓库是最安全的做法。除此之外,本库直接使用 `gopkg.in` 来进行版本化发布。(其实真相是导入路径更短了) ================================================ FILE: vendor/github.com/go-ini/ini/error.go ================================================ // Copyright 2016 Unknwon // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package ini import ( "fmt" ) type ErrDelimiterNotFound struct { Line string } func IsErrDelimiterNotFound(err error) bool { _, ok := err.(ErrDelimiterNotFound) return ok } func (err ErrDelimiterNotFound) Error() string { return fmt.Sprintf("key-value delimiter not found: %s", err.Line) } ================================================ FILE: vendor/github.com/go-ini/ini/ini.go ================================================ // Copyright 2014 Unknwon // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. // Package ini provides INI file read and write functionality in Go. package ini import ( "bytes" "errors" "fmt" "io" "os" "regexp" "runtime" "strconv" "strings" "sync" "time" ) const ( // Name for default section. You can use this constant or the string literal. // In most of cases, an empty string is all you need to access the section. DEFAULT_SECTION = "DEFAULT" // Maximum allowed depth when recursively substituing variable names. _DEPTH_VALUES = 99 _VERSION = "1.21.1" ) // Version returns current package version literal. func Version() string { return _VERSION } var ( // Delimiter to determine or compose a new line. // This variable will be changed to "\r\n" automatically on Windows // at package init time. LineBreak = "\n" // Variable regexp pattern: %(variable)s varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`) // Indicate whether to align "=" sign with spaces to produce pretty output // or reduce all possible spaces for compact format. PrettyFormat = true // Explicitly write DEFAULT section header DefaultHeader = false ) func init() { if runtime.GOOS == "windows" { LineBreak = "\r\n" } } func inSlice(str string, s []string) bool { for _, v := range s { if str == v { return true } } return false } // dataSource is an interface that returns object which can be read and closed. type dataSource interface { ReadCloser() (io.ReadCloser, error) } // sourceFile represents an object that contains content on the local file system. type sourceFile struct { name string } func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { return os.Open(s.name) } type bytesReadCloser struct { reader io.Reader } func (rc *bytesReadCloser) Read(p []byte) (n int, err error) { return rc.reader.Read(p) } func (rc *bytesReadCloser) Close() error { return nil } // sourceData represents an object that contains content in memory. type sourceData struct { data []byte } func (s *sourceData) ReadCloser() (io.ReadCloser, error) { return &bytesReadCloser{bytes.NewReader(s.data)}, nil } // File represents a combination of a or more INI file(s) in memory. type File struct { // Should make things safe, but sometimes doesn't matter. BlockMode bool // Make sure data is safe in multiple goroutines. lock sync.RWMutex // Allow combination of multiple data sources. dataSources []dataSource // Actual data is stored here. sections map[string]*Section // To keep data in order. sectionList []string options LoadOptions NameMapper ValueMapper } // newFile initializes File object with given data sources. func newFile(dataSources []dataSource, opts LoadOptions) *File { return &File{ BlockMode: true, dataSources: dataSources, sections: make(map[string]*Section), sectionList: make([]string, 0, 10), options: opts, } } func parseDataSource(source interface{}) (dataSource, error) { switch s := source.(type) { case string: return sourceFile{s}, nil case []byte: return &sourceData{s}, nil default: return nil, fmt.Errorf("error parsing data source: unknown type '%s'", s) } } type LoadOptions struct { // Loose indicates whether the parser should ignore nonexistent files or return error. Loose bool // Insensitive indicates whether the parser forces all section and key names to lowercase. Insensitive bool // IgnoreContinuation indicates whether to ignore continuation lines while parsing. IgnoreContinuation bool // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. // This type of keys are mostly used in my.cnf. AllowBooleanKeys bool } func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { sources := make([]dataSource, len(others)+1) sources[0], err = parseDataSource(source) if err != nil { return nil, err } for i := range others { sources[i+1], err = parseDataSource(others[i]) if err != nil { return nil, err } } f := newFile(sources, opts) if err = f.Reload(); err != nil { return nil, err } return f, nil } // Load loads and parses from INI data sources. // Arguments can be mixed of file name with string type, or raw data in []byte. // It will return error if list contains nonexistent files. func Load(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{}, source, others...) } // LooseLoad has exactly same functionality as Load function // except it ignores nonexistent files instead of returning error. func LooseLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Loose: true}, source, others...) } // InsensitiveLoad has exactly same functionality as Load function // except it forces all section and key names to be lowercased. func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { return LoadSources(LoadOptions{Insensitive: true}, source, others...) } // Empty returns an empty file object. func Empty() *File { // Ignore error here, we sure our data is good. f, _ := Load([]byte("")) return f } // NewSection creates a new section. func (f *File) NewSection(name string) (*Section, error) { if len(name) == 0 { return nil, errors.New("error creating new section: empty section name") } else if f.options.Insensitive && name != DEFAULT_SECTION { name = strings.ToLower(name) } if f.BlockMode { f.lock.Lock() defer f.lock.Unlock() } if inSlice(name, f.sectionList) { return f.sections[name], nil } f.sectionList = append(f.sectionList, name) f.sections[name] = newSection(f, name) return f.sections[name], nil } // NewSections creates a list of sections. func (f *File) NewSections(names ...string) (err error) { for _, name := range names { if _, err = f.NewSection(name); err != nil { return err } } return nil } // GetSection returns section by given name. func (f *File) GetSection(name string) (*Section, error) { if len(name) == 0 { name = DEFAULT_SECTION } else if f.options.Insensitive { name = strings.ToLower(name) } if f.BlockMode { f.lock.RLock() defer f.lock.RUnlock() } sec := f.sections[name] if sec == nil { return nil, fmt.Errorf("section '%s' does not exist", name) } return sec, nil } // Section assumes named section exists and returns a zero-value when not. func (f *File) Section(name string) *Section { sec, err := f.GetSection(name) if err != nil { // Note: It's OK here because the only possible error is empty section name, // but if it's empty, this piece of code won't be executed. sec, _ = f.NewSection(name) return sec } return sec } // Section returns list of Section. func (f *File) Sections() []*Section { sections := make([]*Section, len(f.sectionList)) for i := range f.sectionList { sections[i] = f.Section(f.sectionList[i]) } return sections } // SectionStrings returns list of section names. func (f *File) SectionStrings() []string { list := make([]string, len(f.sectionList)) copy(list, f.sectionList) return list } // DeleteSection deletes a section. func (f *File) DeleteSection(name string) { if f.BlockMode { f.lock.Lock() defer f.lock.Unlock() } if len(name) == 0 { name = DEFAULT_SECTION } for i, s := range f.sectionList { if s == name { f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...) delete(f.sections, name) return } } } func (f *File) reload(s dataSource) error { r, err := s.ReadCloser() if err != nil { return err } defer r.Close() return f.parse(r) } // Reload reloads and parses all data sources. func (f *File) Reload() (err error) { for _, s := range f.dataSources { if err = f.reload(s); err != nil { // In loose mode, we create an empty default section for nonexistent files. if os.IsNotExist(err) && f.options.Loose { f.parse(bytes.NewBuffer(nil)) continue } return err } } return nil } // Append appends one or more data sources and reloads automatically. func (f *File) Append(source interface{}, others ...interface{}) error { ds, err := parseDataSource(source) if err != nil { return err } f.dataSources = append(f.dataSources, ds) for _, s := range others { ds, err = parseDataSource(s) if err != nil { return err } f.dataSources = append(f.dataSources, ds) } return f.Reload() } // WriteToIndent writes content into io.Writer with given indention. // If PrettyFormat has been set to be true, // it will align "=" sign with spaces under each section. func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) { equalSign := "=" if PrettyFormat { equalSign = " = " } // Use buffer to make sure target is safe until finish encoding. buf := bytes.NewBuffer(nil) for i, sname := range f.sectionList { sec := f.Section(sname) if len(sec.Comment) > 0 { if sec.Comment[0] != '#' && sec.Comment[0] != ';' { sec.Comment = "; " + sec.Comment } if _, err = buf.WriteString(sec.Comment + LineBreak); err != nil { return 0, err } } if i > 0 || DefaultHeader { if _, err = buf.WriteString("[" + sname + "]" + LineBreak); err != nil { return 0, err } } else { // Write nothing if default section is empty if len(sec.keyList) == 0 { continue } } // Count and generate alignment length and buffer spaces using the // longest key. Keys may be modifed if they contain certain characters so // we need to take that into account in our calculation. alignLength := 0 if PrettyFormat { for _, kname := range sec.keyList { keyLength := len(kname) // First case will surround key by ` and second by """ if strings.ContainsAny(kname, "\"=:") { keyLength += 2 } else if strings.Contains(kname, "`") { keyLength += 6 } if keyLength > alignLength { alignLength = keyLength } } } alignSpaces := bytes.Repeat([]byte(" "), alignLength) for _, kname := range sec.keyList { key := sec.Key(kname) if len(key.Comment) > 0 { if len(indent) > 0 && sname != DEFAULT_SECTION { buf.WriteString(indent) } if key.Comment[0] != '#' && key.Comment[0] != ';' { key.Comment = "; " + key.Comment } if _, err = buf.WriteString(key.Comment + LineBreak); err != nil { return 0, err } } if len(indent) > 0 && sname != DEFAULT_SECTION { buf.WriteString(indent) } switch { case key.isAutoIncrement: kname = "-" case strings.ContainsAny(kname, "\"=:"): kname = "`" + kname + "`" case strings.Contains(kname, "`"): kname = `"""` + kname + `"""` } if _, err = buf.WriteString(kname); err != nil { return 0, err } if key.isBooleanType { continue } // Write out alignment spaces before "=" sign if PrettyFormat { buf.Write(alignSpaces[:alignLength-len(kname)]) } val := key.value // In case key value contains "\n", "`", "\"", "#" or ";" if strings.ContainsAny(val, "\n`") { val = `"""` + val + `"""` } else if strings.ContainsAny(val, "#;") { val = "`" + val + "`" } if _, err = buf.WriteString(equalSign + val + LineBreak); err != nil { return 0, err } } // Put a line between sections if _, err = buf.WriteString(LineBreak); err != nil { return 0, err } } return buf.WriteTo(w) } // WriteTo writes file content into io.Writer. func (f *File) WriteTo(w io.Writer) (int64, error) { return f.WriteToIndent(w, "") } // SaveToIndent writes content to file system with given value indention. func (f *File) SaveToIndent(filename, indent string) error { // Note: Because we are truncating with os.Create, // so it's safer to save to a temporary file location and rename afte done. tmpPath := filename + "." + strconv.Itoa(time.Now().Nanosecond()) + ".tmp" defer os.Remove(tmpPath) fw, err := os.Create(tmpPath) if err != nil { return err } if _, err = f.WriteToIndent(fw, indent); err != nil { fw.Close() return err } fw.Close() // Remove old file and rename the new one. os.Remove(filename) return os.Rename(tmpPath, filename) } // SaveTo writes content to file system. func (f *File) SaveTo(filename string) error { return f.SaveToIndent(filename, "") } ================================================ FILE: vendor/github.com/go-ini/ini/key.go ================================================ // Copyright 2014 Unknwon // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package ini import ( "fmt" "strconv" "strings" "time" ) // Key represents a key under a section. type Key struct { s *Section name string value string isAutoIncrement bool isBooleanType bool Comment string } // ValueMapper represents a mapping function for values, e.g. os.ExpandEnv type ValueMapper func(string) string // Name returns name of key. func (k *Key) Name() string { return k.name } // Value returns raw value of key for performance purpose. func (k *Key) Value() string { return k.value } // String returns string representation of value. func (k *Key) String() string { val := k.value if k.s.f.ValueMapper != nil { val = k.s.f.ValueMapper(val) } if strings.Index(val, "%") == -1 { return val } for i := 0; i < _DEPTH_VALUES; i++ { vr := varPattern.FindString(val) if len(vr) == 0 { break } // Take off leading '%(' and trailing ')s'. noption := strings.TrimLeft(vr, "%(") noption = strings.TrimRight(noption, ")s") // Search in the same section. nk, err := k.s.GetKey(noption) if err != nil { // Search again in default section. nk, _ = k.s.f.Section("").GetKey(noption) } // Substitute by new value and take off leading '%(' and trailing ')s'. val = strings.Replace(val, vr, nk.value, -1) } return val } // Validate accepts a validate function which can // return modifed result as key value. func (k *Key) Validate(fn func(string) string) string { return fn(k.String()) } // parseBool returns the boolean value represented by the string. // // It accepts 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On, // 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off. // Any other value returns an error. func parseBool(str string) (value bool, err error) { switch str { case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On": return true, nil case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off": return false, nil } return false, fmt.Errorf("parsing \"%s\": invalid syntax", str) } // Bool returns bool type value. func (k *Key) Bool() (bool, error) { return parseBool(k.String()) } // Float64 returns float64 type value. func (k *Key) Float64() (float64, error) { return strconv.ParseFloat(k.String(), 64) } // Int returns int type value. func (k *Key) Int() (int, error) { return strconv.Atoi(k.String()) } // Int64 returns int64 type value. func (k *Key) Int64() (int64, error) { return strconv.ParseInt(k.String(), 10, 64) } // Uint returns uint type valued. func (k *Key) Uint() (uint, error) { u, e := strconv.ParseUint(k.String(), 10, 64) return uint(u), e } // Uint64 returns uint64 type value. func (k *Key) Uint64() (uint64, error) { return strconv.ParseUint(k.String(), 10, 64) } // Duration returns time.Duration type value. func (k *Key) Duration() (time.Duration, error) { return time.ParseDuration(k.String()) } // TimeFormat parses with given format and returns time.Time type value. func (k *Key) TimeFormat(format string) (time.Time, error) { return time.Parse(format, k.String()) } // Time parses with RFC3339 format and returns time.Time type value. func (k *Key) Time() (time.Time, error) { return k.TimeFormat(time.RFC3339) } // MustString returns default value if key value is empty. func (k *Key) MustString(defaultVal string) string { val := k.String() if len(val) == 0 { k.value = defaultVal return defaultVal } return val } // MustBool always returns value without error, // it returns false if error occurs. func (k *Key) MustBool(defaultVal ...bool) bool { val, err := k.Bool() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatBool(defaultVal[0]) return defaultVal[0] } return val } // MustFloat64 always returns value without error, // it returns 0.0 if error occurs. func (k *Key) MustFloat64(defaultVal ...float64) float64 { val, err := k.Float64() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatFloat(defaultVal[0], 'f', -1, 64) return defaultVal[0] } return val } // MustInt always returns value without error, // it returns 0 if error occurs. func (k *Key) MustInt(defaultVal ...int) int { val, err := k.Int() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatInt(int64(defaultVal[0]), 10) return defaultVal[0] } return val } // MustInt64 always returns value without error, // it returns 0 if error occurs. func (k *Key) MustInt64(defaultVal ...int64) int64 { val, err := k.Int64() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatInt(defaultVal[0], 10) return defaultVal[0] } return val } // MustUint always returns value without error, // it returns 0 if error occurs. func (k *Key) MustUint(defaultVal ...uint) uint { val, err := k.Uint() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatUint(uint64(defaultVal[0]), 10) return defaultVal[0] } return val } // MustUint64 always returns value without error, // it returns 0 if error occurs. func (k *Key) MustUint64(defaultVal ...uint64) uint64 { val, err := k.Uint64() if len(defaultVal) > 0 && err != nil { k.value = strconv.FormatUint(defaultVal[0], 10) return defaultVal[0] } return val } // MustDuration always returns value without error, // it returns zero value if error occurs. func (k *Key) MustDuration(defaultVal ...time.Duration) time.Duration { val, err := k.Duration() if len(defaultVal) > 0 && err != nil { k.value = defaultVal[0].String() return defaultVal[0] } return val } // MustTimeFormat always parses with given format and returns value without error, // it returns zero value if error occurs. func (k *Key) MustTimeFormat(format string, defaultVal ...time.Time) time.Time { val, err := k.TimeFormat(format) if len(defaultVal) > 0 && err != nil { k.value = defaultVal[0].Format(format) return defaultVal[0] } return val } // MustTime always parses with RFC3339 format and returns value without error, // it returns zero value if error occurs. func (k *Key) MustTime(defaultVal ...time.Time) time.Time { return k.MustTimeFormat(time.RFC3339, defaultVal...) } // In always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) In(defaultVal string, candidates []string) string { val := k.String() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InFloat64 always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 { val := k.MustFloat64() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InInt always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InInt(defaultVal int, candidates []int) int { val := k.MustInt() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InInt64 always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 { val := k.MustInt64() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InUint always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InUint(defaultVal uint, candidates []uint) uint { val := k.MustUint() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InUint64 always returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InUint64(defaultVal uint64, candidates []uint64) uint64 { val := k.MustUint64() for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InTimeFormat always parses with given format and returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InTimeFormat(format string, defaultVal time.Time, candidates []time.Time) time.Time { val := k.MustTimeFormat(format) for _, cand := range candidates { if val == cand { return val } } return defaultVal } // InTime always parses with RFC3339 format and returns value without error, // it returns default value if error occurs or doesn't fit into candidates. func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time { return k.InTimeFormat(time.RFC3339, defaultVal, candidates) } // RangeFloat64 checks if value is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeFloat64(defaultVal, min, max float64) float64 { val := k.MustFloat64() if val < min || val > max { return defaultVal } return val } // RangeInt checks if value is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeInt(defaultVal, min, max int) int { val := k.MustInt() if val < min || val > max { return defaultVal } return val } // RangeInt64 checks if value is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeInt64(defaultVal, min, max int64) int64 { val := k.MustInt64() if val < min || val > max { return defaultVal } return val } // RangeTimeFormat checks if value with given format is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeTimeFormat(format string, defaultVal, min, max time.Time) time.Time { val := k.MustTimeFormat(format) if val.Unix() < min.Unix() || val.Unix() > max.Unix() { return defaultVal } return val } // RangeTime checks if value with RFC3339 format is in given range inclusively, // and returns default value if it's not. func (k *Key) RangeTime(defaultVal, min, max time.Time) time.Time { return k.RangeTimeFormat(time.RFC3339, defaultVal, min, max) } // Strings returns list of string divided by given delimiter. func (k *Key) Strings(delim string) []string { str := k.String() if len(str) == 0 { return []string{} } vals := strings.Split(str, delim) for i := range vals { vals[i] = strings.TrimSpace(vals[i]) } return vals } // Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Float64s(delim string) []float64 { vals, _ := k.getFloat64s(delim, true, false) return vals } // Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Ints(delim string) []int { vals, _ := k.getInts(delim, true, false) return vals } // Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Int64s(delim string) []int64 { vals, _ := k.getInt64s(delim, true, false) return vals } // Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uints(delim string) []uint { vals, _ := k.getUints(delim, true, false) return vals } // Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value. func (k *Key) Uint64s(delim string) []uint64 { vals, _ := k.getUint64s(delim, true, false) return vals } // TimesFormat parses with given format and returns list of time.Time divided by given delimiter. // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). func (k *Key) TimesFormat(format, delim string) []time.Time { vals, _ := k.getTimesFormat(format, delim, true, false) return vals } // Times parses with RFC3339 format and returns list of time.Time divided by given delimiter. // Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). func (k *Key) Times(delim string) []time.Time { return k.TimesFormat(time.RFC3339, delim) } // ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then // it will not be included to result list. func (k *Key) ValidFloat64s(delim string) []float64 { vals, _ := k.getFloat64s(delim, false, false) return vals } // ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will // not be included to result list. func (k *Key) ValidInts(delim string) []int { vals, _ := k.getInts(delim, false, false) return vals } // ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer, // then it will not be included to result list. func (k *Key) ValidInt64s(delim string) []int64 { vals, _ := k.getInt64s(delim, false, false) return vals } // ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer, // then it will not be included to result list. func (k *Key) ValidUints(delim string) []uint { vals, _ := k.getUints(delim, false, false) return vals } // ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned // integer, then it will not be included to result list. func (k *Key) ValidUint64s(delim string) []uint64 { vals, _ := k.getUint64s(delim, false, false) return vals } // ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. func (k *Key) ValidTimesFormat(format, delim string) []time.Time { vals, _ := k.getTimesFormat(format, delim, false, false) return vals } // ValidTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter. func (k *Key) ValidTimes(delim string) []time.Time { return k.ValidTimesFormat(time.RFC3339, delim) } // StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input. func (k *Key) StrictFloat64s(delim string) ([]float64, error) { return k.getFloat64s(delim, false, true) } // StrictInts returns list of int divided by given delimiter or error on first invalid input. func (k *Key) StrictInts(delim string) ([]int, error) { return k.getInts(delim, false, true) } // StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input. func (k *Key) StrictInt64s(delim string) ([]int64, error) { return k.getInt64s(delim, false, true) } // StrictUints returns list of uint divided by given delimiter or error on first invalid input. func (k *Key) StrictUints(delim string) ([]uint, error) { return k.getUints(delim, false, true) } // StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input. func (k *Key) StrictUint64s(delim string) ([]uint64, error) { return k.getUint64s(delim, false, true) } // StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter // or error on first invalid input. func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { return k.getTimesFormat(format, delim, false, true) } // StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter // or error on first invalid input. func (k *Key) StrictTimes(delim string) ([]time.Time, error) { return k.StrictTimesFormat(time.RFC3339, delim) } // getFloat64s returns list of float64 divided by given delimiter. func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]float64, error) { strs := k.Strings(delim) vals := make([]float64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseFloat(str, 64) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // getInts returns list of int divided by given delimiter. func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, error) { strs := k.Strings(delim) vals := make([]int, 0, len(strs)) for _, str := range strs { val, err := strconv.Atoi(str) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // getInt64s returns list of int64 divided by given delimiter. func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64, error) { strs := k.Strings(delim) vals := make([]int64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseInt(str, 10, 64) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // getUints returns list of uint divided by given delimiter. func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint, error) { strs := k.Strings(delim) vals := make([]uint, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 0) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, uint(val)) } } return vals, nil } // getUint64s returns list of uint64 divided by given delimiter. func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint64, error) { strs := k.Strings(delim) vals := make([]uint64, 0, len(strs)) for _, str := range strs { val, err := strconv.ParseUint(str, 10, 64) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // getTimesFormat parses with given format and returns list of time.Time divided by given delimiter. func (k *Key) getTimesFormat(format, delim string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { strs := k.Strings(delim) vals := make([]time.Time, 0, len(strs)) for _, str := range strs { val, err := time.Parse(format, str) if err != nil && returnOnInvalid { return nil, err } if err == nil || addInvalid { vals = append(vals, val) } } return vals, nil } // SetValue changes key value. func (k *Key) SetValue(v string) { if k.s.f.BlockMode { k.s.f.lock.Lock() defer k.s.f.lock.Unlock() } k.value = v k.s.keysHash[k.name] = v } ================================================ FILE: vendor/github.com/go-ini/ini/parser.go ================================================ // Copyright 2015 Unknwon // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package ini import ( "bufio" "bytes" "fmt" "io" "strconv" "strings" "unicode" ) type tokenType int const ( _TOKEN_INVALID tokenType = iota _TOKEN_COMMENT _TOKEN_SECTION _TOKEN_KEY ) type parser struct { buf *bufio.Reader isEOF bool count int comment *bytes.Buffer } func newParser(r io.Reader) *parser { return &parser{ buf: bufio.NewReader(r), count: 1, comment: &bytes.Buffer{}, } } // BOM handles header of BOM-UTF8 format. // http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding func (p *parser) BOM() error { mask, err := p.buf.Peek(3) if err != nil && err != io.EOF { return err } else if len(mask) < 3 { return nil } else if mask[0] == 239 && mask[1] == 187 && mask[2] == 191 { p.buf.Read(mask) } return nil } func (p *parser) readUntil(delim byte) ([]byte, error) { data, err := p.buf.ReadBytes(delim) if err != nil { if err == io.EOF { p.isEOF = true } else { return nil, err } } return data, nil } func cleanComment(in []byte) ([]byte, bool) { i := bytes.IndexAny(in, "#;") if i == -1 { return nil, false } return in[i:], true } func readKeyName(in []byte) (string, int, error) { line := string(in) // Check if key name surrounded by quotes. var keyQuote string if line[0] == '"' { if len(line) > 6 && string(line[0:3]) == `"""` { keyQuote = `"""` } else { keyQuote = `"` } } else if line[0] == '`' { keyQuote = "`" } // Get out key name endIdx := -1 if len(keyQuote) > 0 { startIdx := len(keyQuote) // FIXME: fail case -> """"""name"""=value pos := strings.Index(line[startIdx:], keyQuote) if pos == -1 { return "", -1, fmt.Errorf("missing closing key quote: %s", line) } pos += startIdx // Find key-value delimiter i := strings.IndexAny(line[pos+startIdx:], "=:") if i < 0 { return "", -1, ErrDelimiterNotFound{line} } endIdx = pos + i return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil } endIdx = strings.IndexAny(line, "=:") if endIdx < 0 { return "", -1, ErrDelimiterNotFound{line} } return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil } func (p *parser) readMultilines(line, val, valQuote string) (string, error) { for { data, err := p.readUntil('\n') if err != nil { return "", err } next := string(data) pos := strings.LastIndex(next, valQuote) if pos > -1 { val += next[:pos] comment, has := cleanComment([]byte(next[pos:])) if has { p.comment.Write(bytes.TrimSpace(comment)) } break } val += next if p.isEOF { return "", fmt.Errorf("missing closing key quote from '%s' to '%s'", line, next) } } return val, nil } func (p *parser) readContinuationLines(val string) (string, error) { for { data, err := p.readUntil('\n') if err != nil { return "", err } next := strings.TrimSpace(string(data)) if len(next) == 0 { break } val += next if val[len(val)-1] != '\\' { break } val = val[:len(val)-1] } return val, nil } // hasSurroundedQuote check if and only if the first and last characters // are quotes \" or \'. // It returns false if any other parts also contain same kind of quotes. func hasSurroundedQuote(in string, quote byte) bool { return len(in) > 2 && in[0] == quote && in[len(in)-1] == quote && strings.IndexByte(in[1:], quote) == len(in)-2 } func (p *parser) readValue(in []byte, ignoreContinuation bool) (string, error) { line := strings.TrimLeftFunc(string(in), unicode.IsSpace) if len(line) == 0 { return "", nil } var valQuote string if len(line) > 3 && string(line[0:3]) == `"""` { valQuote = `"""` } else if line[0] == '`' { valQuote = "`" } if len(valQuote) > 0 { startIdx := len(valQuote) pos := strings.LastIndex(line[startIdx:], valQuote) // Check for multi-line value if pos == -1 { return p.readMultilines(line, line[startIdx:], valQuote) } return line[startIdx : pos+startIdx], nil } // Won't be able to reach here if value only contains whitespace. line = strings.TrimSpace(line) // Check continuation lines when desired. if !ignoreContinuation && line[len(line)-1] == '\\' { return p.readContinuationLines(line[:len(line)-1]) } i := strings.IndexAny(line, "#;") if i > -1 { p.comment.WriteString(line[i:]) line = strings.TrimSpace(line[:i]) } // Trim single quotes if hasSurroundedQuote(line, '\'') || hasSurroundedQuote(line, '"') { line = line[1 : len(line)-1] } return line, nil } // parse parses data through an io.Reader. func (f *File) parse(reader io.Reader) (err error) { p := newParser(reader) if err = p.BOM(); err != nil { return fmt.Errorf("BOM: %v", err) } // Ignore error because default section name is never empty string. section, _ := f.NewSection(DEFAULT_SECTION) var line []byte for !p.isEOF { line, err = p.readUntil('\n') if err != nil { return err } line = bytes.TrimLeftFunc(line, unicode.IsSpace) if len(line) == 0 { continue } // Comments if line[0] == '#' || line[0] == ';' { // Note: we do not care ending line break, // it is needed for adding second line, // so just clean it once at the end when set to value. p.comment.Write(line) continue } // Section if line[0] == '[' { // Read to the next ']' (TODO: support quoted strings) // TODO(unknwon): use LastIndexByte when stop supporting Go1.4 closeIdx := bytes.LastIndex(line, []byte("]")) if closeIdx == -1 { return fmt.Errorf("unclosed section: %s", line) } name := string(line[1:closeIdx]) section, err = f.NewSection(name) if err != nil { return err } comment, has := cleanComment(line[closeIdx+1:]) if has { p.comment.Write(comment) } section.Comment = strings.TrimSpace(p.comment.String()) // Reset aotu-counter and comments p.comment.Reset() p.count = 1 continue } kname, offset, err := readKeyName(line) if err != nil { // Treat as boolean key when desired, and whole line is key name. if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys { key, err := section.NewKey(string(line), "true") if err != nil { return err } key.isBooleanType = true key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() continue } return err } // Auto increment. isAutoIncr := false if kname == "-" { isAutoIncr = true kname = "#" + strconv.Itoa(p.count) p.count++ } key, err := section.NewKey(kname, "") if err != nil { return err } key.isAutoIncrement = isAutoIncr value, err := p.readValue(line[offset:], f.options.IgnoreContinuation) if err != nil { return err } key.SetValue(value) key.Comment = strings.TrimSpace(p.comment.String()) p.comment.Reset() } return nil } ================================================ FILE: vendor/github.com/go-ini/ini/section.go ================================================ // Copyright 2014 Unknwon // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package ini import ( "errors" "fmt" "strings" ) // Section represents a config section. type Section struct { f *File Comment string name string keys map[string]*Key keyList []string keysHash map[string]string } func newSection(f *File, name string) *Section { return &Section{f, "", name, make(map[string]*Key), make([]string, 0, 10), make(map[string]string)} } // Name returns name of Section. func (s *Section) Name() string { return s.name } // NewKey creates a new key to given section. func (s *Section) NewKey(name, val string) (*Key, error) { if len(name) == 0 { return nil, errors.New("error creating new key: empty key name") } else if s.f.options.Insensitive { name = strings.ToLower(name) } if s.f.BlockMode { s.f.lock.Lock() defer s.f.lock.Unlock() } if inSlice(name, s.keyList) { s.keys[name].value = val return s.keys[name], nil } s.keyList = append(s.keyList, name) s.keys[name] = &Key{ s: s, name: name, value: val, } s.keysHash[name] = val return s.keys[name], nil } // GetKey returns key in section by given name. func (s *Section) GetKey(name string) (*Key, error) { // FIXME: change to section level lock? if s.f.BlockMode { s.f.lock.RLock() } if s.f.options.Insensitive { name = strings.ToLower(name) } key := s.keys[name] if s.f.BlockMode { s.f.lock.RUnlock() } if key == nil { // Check if it is a child-section. sname := s.name for { if i := strings.LastIndex(sname, "."); i > -1 { sname = sname[:i] sec, err := s.f.GetSection(sname) if err != nil { continue } return sec.GetKey(name) } else { break } } return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name) } return key, nil } // HasKey returns true if section contains a key with given name. func (s *Section) HasKey(name string) bool { key, _ := s.GetKey(name) return key != nil } // Haskey is a backwards-compatible name for HasKey. func (s *Section) Haskey(name string) bool { return s.HasKey(name) } // HasValue returns true if section contains given raw value. func (s *Section) HasValue(value string) bool { if s.f.BlockMode { s.f.lock.RLock() defer s.f.lock.RUnlock() } for _, k := range s.keys { if value == k.value { return true } } return false } // Key assumes named Key exists in section and returns a zero-value when not. func (s *Section) Key(name string) *Key { key, err := s.GetKey(name) if err != nil { // It's OK here because the only possible error is empty key name, // but if it's empty, this piece of code won't be executed. key, _ = s.NewKey(name, "") return key } return key } // Keys returns list of keys of section. func (s *Section) Keys() []*Key { keys := make([]*Key, len(s.keyList)) for i := range s.keyList { keys[i] = s.Key(s.keyList[i]) } return keys } // ParentKeys returns list of keys of parent section. func (s *Section) ParentKeys() []*Key { var parentKeys []*Key sname := s.name for { if i := strings.LastIndex(sname, "."); i > -1 { sname = sname[:i] sec, err := s.f.GetSection(sname) if err != nil { continue } parentKeys = append(parentKeys, sec.Keys()...) } else { break } } return parentKeys } // KeyStrings returns list of key names of section. func (s *Section) KeyStrings() []string { list := make([]string, len(s.keyList)) copy(list, s.keyList) return list } // KeysHash returns keys hash consisting of names and values. func (s *Section) KeysHash() map[string]string { if s.f.BlockMode { s.f.lock.RLock() defer s.f.lock.RUnlock() } hash := map[string]string{} for key, value := range s.keysHash { hash[key] = value } return hash } // DeleteKey deletes a key from section. func (s *Section) DeleteKey(name string) { if s.f.BlockMode { s.f.lock.Lock() defer s.f.lock.Unlock() } for i, k := range s.keyList { if k == name { s.keyList = append(s.keyList[:i], s.keyList[i+1:]...) delete(s.keys, name) return } } } ================================================ FILE: vendor/github.com/go-ini/ini/struct.go ================================================ // Copyright 2014 Unknwon // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package ini import ( "bytes" "errors" "fmt" "reflect" "strings" "time" "unicode" ) // NameMapper represents a ini tag name mapper. type NameMapper func(string) string // Built-in name getters. var ( // AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. AllCapsUnderscore NameMapper = func(raw string) string { newstr := make([]rune, 0, len(raw)) for i, chr := range raw { if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { if i > 0 { newstr = append(newstr, '_') } } newstr = append(newstr, unicode.ToUpper(chr)) } return string(newstr) } // TitleUnderscore converts to format title_underscore. TitleUnderscore NameMapper = func(raw string) string { newstr := make([]rune, 0, len(raw)) for i, chr := range raw { if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { if i > 0 { newstr = append(newstr, '_') } chr -= ('A' - 'a') } newstr = append(newstr, chr) } return string(newstr) } ) func (s *Section) parseFieldName(raw, actual string) string { if len(actual) > 0 { return actual } if s.f.NameMapper != nil { return s.f.NameMapper(raw) } return raw } func parseDelim(actual string) string { if len(actual) > 0 { return actual } return "," } var reflectTime = reflect.TypeOf(time.Now()).Kind() // setSliceWithProperType sets proper values to slice based on its type. func setSliceWithProperType(key *Key, field reflect.Value, delim string) error { strs := key.Strings(delim) numVals := len(strs) if numVals == 0 { return nil } var vals interface{} sliceOf := field.Type().Elem().Kind() switch sliceOf { case reflect.String: vals = strs case reflect.Int: vals = key.Ints(delim) case reflect.Int64: vals = key.Int64s(delim) case reflect.Uint: vals = key.Uints(delim) case reflect.Uint64: vals = key.Uint64s(delim) case reflect.Float64: vals = key.Float64s(delim) case reflectTime: vals = key.Times(delim) default: return fmt.Errorf("unsupported type '[]%s'", sliceOf) } slice := reflect.MakeSlice(field.Type(), numVals, numVals) for i := 0; i < numVals; i++ { switch sliceOf { case reflect.String: slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i])) case reflect.Int: slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i])) case reflect.Int64: slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i])) case reflect.Uint: slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i])) case reflect.Uint64: slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) case reflect.Float64: slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) case reflectTime: slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) } } field.Set(slice) return nil } // setWithProperType sets proper value to field based on its type, // but it does not return error for failing parsing, // because we want to use default value that is already assigned to strcut. func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { switch t.Kind() { case reflect.String: if len(key.String()) == 0 { return nil } field.SetString(key.String()) case reflect.Bool: boolVal, err := key.Bool() if err != nil { return nil } field.SetBool(boolVal) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: durationVal, err := key.Duration() // Skip zero value if err == nil && int(durationVal) > 0 { field.Set(reflect.ValueOf(durationVal)) return nil } intVal, err := key.Int64() if err != nil || intVal == 0 { return nil } field.SetInt(intVal) // byte is an alias for uint8, so supporting uint8 breaks support for byte case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: durationVal, err := key.Duration() // Skip zero value if err == nil && int(durationVal) > 0 { field.Set(reflect.ValueOf(durationVal)) return nil } uintVal, err := key.Uint64() if err != nil { return nil } field.SetUint(uintVal) case reflect.Float64: floatVal, err := key.Float64() if err != nil { return nil } field.SetFloat(floatVal) case reflectTime: timeVal, err := key.Time() if err != nil { return nil } field.Set(reflect.ValueOf(timeVal)) case reflect.Slice: return setSliceWithProperType(key, field, delim) default: return fmt.Errorf("unsupported type '%s'", t) } return nil } func (s *Section) mapTo(val reflect.Value) error { if val.Kind() == reflect.Ptr { val = val.Elem() } typ := val.Type() for i := 0; i < typ.NumField(); i++ { field := val.Field(i) tpField := typ.Field(i) tag := tpField.Tag.Get("ini") if tag == "-" { continue } opts := strings.SplitN(tag, ",", 2) // strip off possible omitempty fieldName := s.parseFieldName(tpField.Name, opts[0]) if len(fieldName) == 0 || !field.CanSet() { continue } isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous isStruct := tpField.Type.Kind() == reflect.Struct if isAnonymous { field.Set(reflect.New(tpField.Type.Elem())) } if isAnonymous || isStruct { if sec, err := s.f.GetSection(fieldName); err == nil { if err = sec.mapTo(field); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } continue } } if key, err := s.GetKey(fieldName); err == nil { if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { return fmt.Errorf("error mapping field(%s): %v", fieldName, err) } } } return nil } // MapTo maps section to given struct. func (s *Section) MapTo(v interface{}) error { typ := reflect.TypeOf(v) val := reflect.ValueOf(v) if typ.Kind() == reflect.Ptr { typ = typ.Elem() val = val.Elem() } else { return errors.New("cannot map to non-pointer struct") } return s.mapTo(val) } // MapTo maps file to given struct. func (f *File) MapTo(v interface{}) error { return f.Section("").MapTo(v) } // MapTo maps data sources to given struct with name mapper. func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { cfg, err := Load(source, others...) if err != nil { return err } cfg.NameMapper = mapper return cfg.MapTo(v) } // MapTo maps data sources to given struct. func MapTo(v, source interface{}, others ...interface{}) error { return MapToWithMapper(v, nil, source, others...) } // reflectSliceWithProperType does the opposite thing as setSliceWithProperType. func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error { slice := field.Slice(0, field.Len()) if field.Len() == 0 { return nil } var buf bytes.Buffer sliceOf := field.Type().Elem().Kind() for i := 0; i < field.Len(); i++ { switch sliceOf { case reflect.String: buf.WriteString(slice.Index(i).String()) case reflect.Int, reflect.Int64: buf.WriteString(fmt.Sprint(slice.Index(i).Int())) case reflect.Uint, reflect.Uint64: buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) case reflect.Float64: buf.WriteString(fmt.Sprint(slice.Index(i).Float())) case reflectTime: buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) default: return fmt.Errorf("unsupported type '[]%s'", sliceOf) } buf.WriteString(delim) } key.SetValue(buf.String()[:buf.Len()-1]) return nil } // reflectWithProperType does the opposite thing as setWithProperType. func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { switch t.Kind() { case reflect.String: key.SetValue(field.String()) case reflect.Bool: key.SetValue(fmt.Sprint(field.Bool())) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: key.SetValue(fmt.Sprint(field.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: key.SetValue(fmt.Sprint(field.Uint())) case reflect.Float32, reflect.Float64: key.SetValue(fmt.Sprint(field.Float())) case reflectTime: key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) case reflect.Slice: return reflectSliceWithProperType(key, field, delim) default: return fmt.Errorf("unsupported type '%s'", t) } return nil } // CR: copied from encoding/json/encode.go with modifications of time.Time support. // TODO: add more test coverage. func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflectTime: return v.Interface().(time.Time).IsZero() case reflect.Interface, reflect.Ptr: return v.IsNil() } return false } func (s *Section) reflectFrom(val reflect.Value) error { if val.Kind() == reflect.Ptr { val = val.Elem() } typ := val.Type() for i := 0; i < typ.NumField(); i++ { field := val.Field(i) tpField := typ.Field(i) tag := tpField.Tag.Get("ini") if tag == "-" { continue } opts := strings.SplitN(tag, ",", 2) if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) { continue } fieldName := s.parseFieldName(tpField.Name, opts[0]) if len(fieldName) == 0 || !field.CanSet() { continue } if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) || (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") { // Note: The only error here is section doesn't exist. sec, err := s.f.GetSection(fieldName) if err != nil { // Note: fieldName can never be empty here, ignore error. sec, _ = s.f.NewSection(fieldName) } if err = sec.reflectFrom(field); err != nil { return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) } continue } // Note: Same reason as secion. key, err := s.GetKey(fieldName) if err != nil { key, _ = s.NewKey(fieldName, "") } if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) } } return nil } // ReflectFrom reflects secion from given struct. func (s *Section) ReflectFrom(v interface{}) error { typ := reflect.TypeOf(v) val := reflect.ValueOf(v) if typ.Kind() == reflect.Ptr { typ = typ.Elem() val = val.Elem() } else { return errors.New("cannot reflect from non-pointer struct") } return s.reflectFrom(val) } // ReflectFrom reflects file from given struct. func (f *File) ReflectFrom(v interface{}) error { return f.Section("").ReflectFrom(v) } // ReflectFrom reflects data sources from given struct with name mapper. func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { cfg.NameMapper = mapper return cfg.ReflectFrom(v) } // ReflectFrom reflects data sources from given struct. func ReflectFrom(cfg *File, v interface{}) error { return ReflectFromWithMapper(cfg, v, nil) } ================================================ FILE: vendor/github.com/hashicorp/hcl/LICENSE ================================================ Mozilla Public License, version 2.0 1. Definitions 1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. “Contributor Version” means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution. 1.3. “Contribution” means Covered Software of a particular Contributor. 1.4. “Covered Software” means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. “Incompatible With Secondary Licenses” means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. “Executable Form” means any form of the work other than Source Code Form. 1.7. “Larger Work” means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. “License” means this document. 1.9. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. “Modifications” means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. “Patent Claims” of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. “Secondary License” means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. “Source Code Form” means the form of the work preferred for making modifications. 1.14. “You” (or “Your”) means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - “Incompatible With Secondary Licenses” Notice This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: vendor/github.com/hashicorp/hcl/Makefile ================================================ TEST?=./... default: test fmt: generate go fmt ./... test: generate go test $(TEST) $(TESTARGS) generate: go generate ./... updatedeps: go get -u golang.org/x/tools/cmd/stringer .PHONY: default generate test updatedeps ================================================ FILE: vendor/github.com/hashicorp/hcl/README.md ================================================ # HCL [![GoDoc](https://godoc.org/github.com/hashicorp/hcl?status.png)](https://godoc.org/github.com/hashicorp/hcl) [![Build Status](https://travis-ci.org/hashicorp/hcl.svg?branch=master)](https://travis-ci.org/hashicorp/hcl) HCL (HashiCorp Configuration Language) is a configuration language built by HashiCorp. The goal of HCL is to build a structured configuration language that is both human and machine friendly for use with command-line tools, but specifically targeted towards DevOps tools, servers, etc. HCL is also fully JSON compatible. That is, JSON can be used as completely valid input to a system expecting HCL. This helps makes systems interoperable with other systems. HCL is heavily inspired by [libucl](https://github.com/vstakhov/libucl), nginx configuration, and others similar. ## Why? A common question when viewing HCL is to ask the question: why not JSON, YAML, etc.? Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com) used a variety of configuration languages from full programming languages such as Ruby to complete data structure languages such as JSON. What we learned is that some people wanted human-friendly configuration languages and some people wanted machine-friendly languages. JSON fits a nice balance in this, but is fairly verbose and most importantly doesn't support comments. With YAML, we found that beginners had a really hard time determining what the actual structure was, and ended up guessing more often than not whether to use a hyphen, colon, etc. in order to represent some configuration key. Full programming languages such as Ruby enable complex behavior a configuration language shouldn't usually allow, and also forces people to learn some set of Ruby. Because of this, we decided to create our own configuration language that is JSON-compatible. Our configuration language (HCL) is designed to be written and modified by humans. The API for HCL allows JSON as an input so that it is also machine-friendly (machines can generate JSON instead of trying to generate HCL). Our goal with HCL is not to alienate other configuration languages. It is instead to provide HCL as a specialized language for our tools, and JSON as the interoperability layer. ## Syntax For a complete grammar, please see the parser itself. A high-level overview of the syntax and grammar is listed here. * Single line comments start with `#` or `//` * Multi-line comments are wrapped in `/*` and `*/`. Nested block comments are not allowed. A multi-line comment (also known as a block comment) terminates at the first `*/` found. * Values are assigned with the syntax `key = value` (whitespace doesn't matter). The value can be any primitive: a string, number, boolean, object, or list. * Strings are double-quoted and can contain any UTF-8 characters. Example: `"Hello, World"` * Multi-line strings start with `<- echo %Path% go version go env build_script: - cmd: go test -v ./... ================================================ FILE: vendor/github.com/hashicorp/hcl/decoder.go ================================================ package hcl import ( "errors" "fmt" "reflect" "sort" "strconv" "strings" "github.com/hashicorp/hcl/hcl/ast" "github.com/hashicorp/hcl/hcl/parser" "github.com/hashicorp/hcl/hcl/token" ) // This is the tag to use with structures to have settings for HCL const tagName = "hcl" var ( // nodeType holds a reference to the type of ast.Node nodeType reflect.Type = findNodeType() ) // Unmarshal accepts a byte slice as input and writes the // data to the value pointed to by v. func Unmarshal(bs []byte, v interface{}) error { root, err := parse(bs) if err != nil { return err } return DecodeObject(v, root) } // Decode reads the given input and decodes it into the structure // given by `out`. func Decode(out interface{}, in string) error { obj, err := Parse(in) if err != nil { return err } return DecodeObject(out, obj) } // DecodeObject is a lower-level version of Decode. It decodes a // raw Object into the given output. func DecodeObject(out interface{}, n ast.Node) error { val := reflect.ValueOf(out) if val.Kind() != reflect.Ptr { return errors.New("result must be a pointer") } // If we have the file, we really decode the root node if f, ok := n.(*ast.File); ok { n = f.Node } var d decoder return d.decode("root", n, val.Elem()) } type decoder struct { stack []reflect.Kind } func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error { k := result // If we have an interface with a valid value, we use that // for the check. if result.Kind() == reflect.Interface { elem := result.Elem() if elem.IsValid() { k = elem } } // Push current onto stack unless it is an interface. if k.Kind() != reflect.Interface { d.stack = append(d.stack, k.Kind()) // Schedule a pop defer func() { d.stack = d.stack[:len(d.stack)-1] }() } switch k.Kind() { case reflect.Bool: return d.decodeBool(name, node, result) case reflect.Float64: return d.decodeFloat(name, node, result) case reflect.Int: return d.decodeInt(name, node, result) case reflect.Interface: // When we see an interface, we make our own thing return d.decodeInterface(name, node, result) case reflect.Map: return d.decodeMap(name, node, result) case reflect.Ptr: return d.decodePtr(name, node, result) case reflect.Slice: return d.decodeSlice(name, node, result) case reflect.String: return d.decodeString(name, node, result) case reflect.Struct: return d.decodeStruct(name, node, result) default: return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), } } } func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error { switch n := node.(type) { case *ast.LiteralType: if n.Token.Type == token.BOOL { v, err := strconv.ParseBool(n.Token.Text) if err != nil { return err } result.Set(reflect.ValueOf(v)) return nil } } return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown type %T", name, node), } } func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { switch n := node.(type) { case *ast.LiteralType: if n.Token.Type == token.FLOAT { v, err := strconv.ParseFloat(n.Token.Text, 64) if err != nil { return err } result.Set(reflect.ValueOf(v)) return nil } } return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown type %T", name, node), } } func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error { switch n := node.(type) { case *ast.LiteralType: switch n.Token.Type { case token.NUMBER: v, err := strconv.ParseInt(n.Token.Text, 0, 0) if err != nil { return err } result.Set(reflect.ValueOf(int(v))) return nil case token.STRING: v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0) if err != nil { return err } result.Set(reflect.ValueOf(int(v))) return nil } } return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown type %T", name, node), } } func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error { // When we see an ast.Node, we retain the value to enable deferred decoding. // Very useful in situations where we want to preserve ast.Node information // like Pos if result.Type() == nodeType && result.CanSet() { result.Set(reflect.ValueOf(node)) return nil } var set reflect.Value redecode := true // For testing types, ObjectType should just be treated as a list. We // set this to a temporary var because we want to pass in the real node. testNode := node if ot, ok := node.(*ast.ObjectType); ok { testNode = ot.List } switch n := testNode.(type) { case *ast.ObjectList: // If we're at the root or we're directly within a slice, then we // decode objects into map[string]interface{}, otherwise we decode // them into lists. if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { var temp map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeMap( reflect.MapOf( reflect.TypeOf(""), tempVal.Type().Elem())) set = result } else { var temp []map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeSlice( reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items)) set = result } case *ast.ObjectType: // If we're at the root or we're directly within a slice, then we // decode objects into map[string]interface{}, otherwise we decode // them into lists. if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { var temp map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeMap( reflect.MapOf( reflect.TypeOf(""), tempVal.Type().Elem())) set = result } else { var temp []map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeSlice( reflect.SliceOf(tempVal.Type().Elem()), 0, 1) set = result } case *ast.ListType: var temp []interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeSlice( reflect.SliceOf(tempVal.Type().Elem()), 0, 0) set = result case *ast.LiteralType: switch n.Token.Type { case token.BOOL: var result bool set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case token.FLOAT: var result float64 set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case token.NUMBER: var result int set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case token.STRING, token.HEREDOC: set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) default: return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node), } } default: return fmt.Errorf( "%s: cannot decode into interface: %T", name, node) } // Set the result to what its supposed to be, then reset // result so we don't reflect into this method anymore. result.Set(set) if redecode { // Revisit the node so that we can use the newly instantiated // thing and populate it. if err := d.decode(name, node, result); err != nil { return err } } return nil } func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error { if item, ok := node.(*ast.ObjectItem); ok { node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} } if ot, ok := node.(*ast.ObjectType); ok { node = ot.List } n, ok := node.(*ast.ObjectList) if !ok { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: not an object type for map (%T)", name, node), } } // If we have an interface, then we can address the interface, // but not the slice itself, so get the element but set the interface set := result if result.Kind() == reflect.Interface { result = result.Elem() } resultType := result.Type() resultElemType := resultType.Elem() resultKeyType := resultType.Key() if resultKeyType.Kind() != reflect.String { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: map must have string keys", name), } } // Make a map if it is nil resultMap := result if result.IsNil() { resultMap = reflect.MakeMap( reflect.MapOf(resultKeyType, resultElemType)) } // Go through each element and decode it. done := make(map[string]struct{}) for _, item := range n.Items { if item.Val == nil { continue } // github.com/hashicorp/terraform/issue/5740 if len(item.Keys) == 0 { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: map must have string keys", name), } } // Get the key we're dealing with, which is the first item keyStr := item.Keys[0].Token.Value().(string) // If we've already processed this key, then ignore it if _, ok := done[keyStr]; ok { continue } // Determine the value. If we have more than one key, then we // get the objectlist of only these keys. itemVal := item.Val if len(item.Keys) > 1 { itemVal = n.Filter(keyStr) done[keyStr] = struct{}{} } // Make the field name fieldName := fmt.Sprintf("%s.%s", name, keyStr) // Get the key/value as reflection values key := reflect.ValueOf(keyStr) val := reflect.Indirect(reflect.New(resultElemType)) // If we have a pre-existing value in the map, use that oldVal := resultMap.MapIndex(key) if oldVal.IsValid() { val.Set(oldVal) } // Decode! if err := d.decode(fieldName, itemVal, val); err != nil { return err } // Set the value on the map resultMap.SetMapIndex(key, val) } // Set the final map if we can set.Set(resultMap) return nil } func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error { // Create an element of the concrete (non pointer) type and decode // into that. Then set the value of the pointer to this type. resultType := result.Type() resultElemType := resultType.Elem() val := reflect.New(resultElemType) if err := d.decode(name, node, reflect.Indirect(val)); err != nil { return err } result.Set(val) return nil } func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error { // If we have an interface, then we can address the interface, // but not the slice itself, so get the element but set the interface set := result if result.Kind() == reflect.Interface { result = result.Elem() } // Create the slice if it isn't nil resultType := result.Type() resultElemType := resultType.Elem() if result.IsNil() { resultSliceType := reflect.SliceOf(resultElemType) result = reflect.MakeSlice( resultSliceType, 0, 0) } // Figure out the items we'll be copying into the slice var items []ast.Node switch n := node.(type) { case *ast.ObjectList: items = make([]ast.Node, len(n.Items)) for i, item := range n.Items { items[i] = item } case *ast.ObjectType: items = []ast.Node{n} case *ast.ListType: items = n.List default: return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("unknown slice type: %T", node), } } for i, item := range items { fieldName := fmt.Sprintf("%s[%d]", name, i) // Decode val := reflect.Indirect(reflect.New(resultElemType)) if err := d.decode(fieldName, item, val); err != nil { return err } // Append it onto the slice result = reflect.Append(result, val) } set.Set(result) return nil } func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error { switch n := node.(type) { case *ast.LiteralType: switch n.Token.Type { case token.NUMBER: result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type())) return nil case token.STRING, token.HEREDOC: result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type())) return nil } } return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown type for string %T", name, node), } } func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error { var item *ast.ObjectItem if it, ok := node.(*ast.ObjectItem); ok { item = it node = it.Val } if ot, ok := node.(*ast.ObjectType); ok { node = ot.List } // Handle the special case where the object itself is a literal. Previously // the yacc parser would always ensure top-level elements were arrays. The new // parser does not make the same guarantees, thus we need to convert any // top-level literal elements into a list. if _, ok := node.(*ast.LiteralType); ok && item != nil { node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} } list, ok := node.(*ast.ObjectList) if !ok { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node), } } // This slice will keep track of all the structs we'll be decoding. // There can be more than one struct if there are embedded structs // that are squashed. structs := make([]reflect.Value, 1, 5) structs[0] = result // Compile the list of all the fields that we're going to be decoding // from all the structs. fields := make(map[*reflect.StructField]reflect.Value) for len(structs) > 0 { structVal := structs[0] structs = structs[1:] structType := structVal.Type() for i := 0; i < structType.NumField(); i++ { fieldType := structType.Field(i) tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") // Ignore fields with tag name "-" if tagParts[0] == "-" { continue } if fieldType.Anonymous { fieldKind := fieldType.Type.Kind() if fieldKind != reflect.Struct { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unsupported type to struct: %s", fieldType.Name, fieldKind), } } // We have an embedded field. We "squash" the fields down // if specified in the tag. squash := false for _, tag := range tagParts[1:] { if tag == "squash" { squash = true break } } if squash { structs = append( structs, result.FieldByName(fieldType.Name)) continue } } // Normal struct field, store it away fields[&fieldType] = structVal.Field(i) } } usedKeys := make(map[string]struct{}) decodedFields := make([]string, 0, len(fields)) decodedFieldsVal := make([]reflect.Value, 0) unusedKeysVal := make([]reflect.Value, 0) for fieldType, field := range fields { if !field.IsValid() { // This should never happen panic("field is not valid") } // If we can't set the field, then it is unexported or something, // and we just continue onwards. if !field.CanSet() { continue } fieldName := fieldType.Name tagValue := fieldType.Tag.Get(tagName) tagParts := strings.SplitN(tagValue, ",", 2) if len(tagParts) >= 2 { switch tagParts[1] { case "decodedFields": decodedFieldsVal = append(decodedFieldsVal, field) continue case "key": if item == nil { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: %s asked for 'key', impossible", name, fieldName), } } field.SetString(item.Keys[0].Token.Value().(string)) continue case "unusedKeys": unusedKeysVal = append(unusedKeysVal, field) continue } } if tagParts[0] != "" { fieldName = tagParts[0] } // Determine the element we'll use to decode. If it is a single // match (only object with the field), then we decode it exactly. // If it is a prefix match, then we decode the matches. filter := list.Filter(fieldName) prefixMatches := filter.Children() matches := filter.Elem() if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 { continue } // Track the used key usedKeys[fieldName] = struct{}{} // Create the field name and decode. We range over the elements // because we actually want the value. fieldName = fmt.Sprintf("%s.%s", name, fieldName) if len(prefixMatches.Items) > 0 { if err := d.decode(fieldName, prefixMatches, field); err != nil { return err } } for _, match := range matches.Items { var decodeNode ast.Node = match.Val if ot, ok := decodeNode.(*ast.ObjectType); ok { decodeNode = &ast.ObjectList{Items: ot.List.Items} } if err := d.decode(fieldName, decodeNode, field); err != nil { return err } } decodedFields = append(decodedFields, fieldType.Name) } if len(decodedFieldsVal) > 0 { // Sort it so that it is deterministic sort.Strings(decodedFields) for _, v := range decodedFieldsVal { v.Set(reflect.ValueOf(decodedFields)) } } return nil } // findNodeType returns the type of ast.Node func findNodeType() reflect.Type { var nodeContainer struct { Node ast.Node } value := reflect.ValueOf(nodeContainer).FieldByName("Node") return value.Type() } ================================================ FILE: vendor/github.com/hashicorp/hcl/hcl/ast/ast.go ================================================ // Package ast declares the types used to represent syntax trees for HCL // (HashiCorp Configuration Language) package ast import ( "fmt" "strings" "github.com/hashicorp/hcl/hcl/token" ) // Node is an element in the abstract syntax tree. type Node interface { node() Pos() token.Pos } func (File) node() {} func (ObjectList) node() {} func (ObjectKey) node() {} func (ObjectItem) node() {} func (Comment) node() {} func (CommentGroup) node() {} func (ObjectType) node() {} func (LiteralType) node() {} func (ListType) node() {} // File represents a single HCL file type File struct { Node Node // usually a *ObjectList Comments []*CommentGroup // list of all comments in the source } func (f *File) Pos() token.Pos { return f.Node.Pos() } // ObjectList represents a list of ObjectItems. An HCL file itself is an // ObjectList. type ObjectList struct { Items []*ObjectItem } func (o *ObjectList) Add(item *ObjectItem) { o.Items = append(o.Items, item) } // Filter filters out the objects with the given key list as a prefix. // // The returned list of objects contain ObjectItems where the keys have // this prefix already stripped off. This might result in objects with // zero-length key lists if they have no children. // // If no matches are found, an empty ObjectList (non-nil) is returned. func (o *ObjectList) Filter(keys ...string) *ObjectList { var result ObjectList for _, item := range o.Items { // If there aren't enough keys, then ignore this if len(item.Keys) < len(keys) { continue } match := true for i, key := range item.Keys[:len(keys)] { key := key.Token.Value().(string) if key != keys[i] && !strings.EqualFold(key, keys[i]) { match = false break } } if !match { continue } // Strip off the prefix from the children newItem := *item newItem.Keys = newItem.Keys[len(keys):] result.Add(&newItem) } return &result } // Children returns further nested objects (key length > 0) within this // ObjectList. This should be used with Filter to get at child items. func (o *ObjectList) Children() *ObjectList { var result ObjectList for _, item := range o.Items { if len(item.Keys) > 0 { result.Add(item) } } return &result } // Elem returns items in the list that are direct element assignments // (key length == 0). This should be used with Filter to get at elements. func (o *ObjectList) Elem() *ObjectList { var result ObjectList for _, item := range o.Items { if len(item.Keys) == 0 { result.Add(item) } } return &result } func (o *ObjectList) Pos() token.Pos { // always returns the uninitiliazed position return o.Items[0].Pos() } // ObjectItem represents a HCL Object Item. An item is represented with a key // (or keys). It can be an assignment or an object (both normal and nested) type ObjectItem struct { // keys is only one length long if it's of type assignment. If it's a // nested object it can be larger than one. In that case "assign" is // invalid as there is no assignments for a nested object. Keys []*ObjectKey // assign contains the position of "=", if any Assign token.Pos // val is the item itself. It can be an object,list, number, bool or a // string. If key length is larger than one, val can be only of type // Object. Val Node LeadComment *CommentGroup // associated lead comment LineComment *CommentGroup // associated line comment } func (o *ObjectItem) Pos() token.Pos { // I'm not entirely sure what causes this, but removing this causes // a test failure. We should investigate at some point. if len(o.Keys) == 0 { return token.Pos{} } return o.Keys[0].Pos() } // ObjectKeys are either an identifier or of type string. type ObjectKey struct { Token token.Token } func (o *ObjectKey) Pos() token.Pos { return o.Token.Pos } // LiteralType represents a literal of basic type. Valid types are: // token.NUMBER, token.FLOAT, token.BOOL and token.STRING type LiteralType struct { Token token.Token // associated line comment, only when used in a list LineComment *CommentGroup } func (l *LiteralType) Pos() token.Pos { return l.Token.Pos } // ListStatement represents a HCL List type type ListType struct { Lbrack token.Pos // position of "[" Rbrack token.Pos // position of "]" List []Node // the elements in lexical order } func (l *ListType) Pos() token.Pos { return l.Lbrack } func (l *ListType) Add(node Node) { l.List = append(l.List, node) } // ObjectType represents a HCL Object Type type ObjectType struct { Lbrace token.Pos // position of "{" Rbrace token.Pos // position of "}" List *ObjectList // the nodes in lexical order } func (o *ObjectType) Pos() token.Pos { return o.Lbrace } // Comment node represents a single //, # style or /*- style commment type Comment struct { Start token.Pos // position of / or # Text string } func (c *Comment) Pos() token.Pos { return c.Start } // CommentGroup node represents a sequence of comments with no other tokens and // no empty lines between. type CommentGroup struct { List []*Comment // len(List) > 0 } func (c *CommentGroup) Pos() token.Pos { return c.List[0].Pos() } //------------------------------------------------------------------- // GoStringer //------------------------------------------------------------------- func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) } func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) } ================================================ FILE: vendor/github.com/hashicorp/hcl/hcl/ast/walk.go ================================================ package ast import "fmt" // WalkFunc describes a function to be called for each node during a Walk. The // returned node can be used to rewrite the AST. Walking stops the returned // bool is false. type WalkFunc func(Node) (Node, bool) // Walk traverses an AST in depth-first order: It starts by calling fn(node); // node must not be nil. If fn returns true, Walk invokes fn recursively for // each of the non-nil children of node, followed by a call of fn(nil). The // returned node of fn can be used to rewrite the passed node to fn. func Walk(node Node, fn WalkFunc) Node { rewritten, ok := fn(node) if !ok { return rewritten } switch n := node.(type) { case *File: n.Node = Walk(n.Node, fn) case *ObjectList: for i, item := range n.Items { n.Items[i] = Walk(item, fn).(*ObjectItem) } case *ObjectKey: // nothing to do case *ObjectItem: for i, k := range n.Keys { n.Keys[i] = Walk(k, fn).(*ObjectKey) } if n.Val != nil { n.Val = Walk(n.Val, fn) } case *LiteralType: // nothing to do case *ListType: for i, l := range n.List { n.List[i] = Walk(l, fn) } case *ObjectType: n.List = Walk(n.List, fn).(*ObjectList) default: // should we panic here? fmt.Printf("unknown type: %T\n", n) } fn(nil) return rewritten } ================================================ FILE: vendor/github.com/hashicorp/hcl/hcl/parser/error.go ================================================ package parser import ( "fmt" "github.com/hashicorp/hcl/hcl/token" ) // PosError is a parse error that contains a position. type PosError struct { Pos token.Pos Err error } func (e *PosError) Error() string { return fmt.Sprintf("At %s: %s", e.Pos, e.Err) } ================================================ FILE: vendor/github.com/hashicorp/hcl/hcl/parser/parser.go ================================================ // Package parser implements a parser for HCL (HashiCorp Configuration // Language) package parser import ( "errors" "fmt" "strings" "github.com/hashicorp/hcl/hcl/ast" "github.com/hashicorp/hcl/hcl/scanner" "github.com/hashicorp/hcl/hcl/token" ) type Parser struct { sc *scanner.Scanner // Last read token tok token.Token commaPrev token.Token comments []*ast.CommentGroup leadComment *ast.CommentGroup // last lead comment lineComment *ast.CommentGroup // last line comment enableTrace bool indent int n int // buffer size (max = 1) } func newParser(src []byte) *Parser { return &Parser{ sc: scanner.New(src), } } // Parse returns the fully parsed source and returns the abstract syntax tree. func Parse(src []byte) (*ast.File, error) { p := newParser(src) return p.Parse() } var errEofToken = errors.New("EOF token found") // Parse returns the fully parsed source and returns the abstract syntax tree. func (p *Parser) Parse() (*ast.File, error) { f := &ast.File{} var err, scerr error p.sc.Error = func(pos token.Pos, msg string) { scerr = &PosError{Pos: pos, Err: errors.New(msg)} } f.Node, err = p.objectList() if scerr != nil { return nil, scerr } if err != nil { return nil, err } f.Comments = p.comments return f, nil } func (p *Parser) objectList() (*ast.ObjectList, error) { defer un(trace(p, "ParseObjectList")) node := &ast.ObjectList{} for { n, err := p.objectItem() if err == errEofToken { break // we are finished } // we don't return a nil node, because might want to use already // collected items. if err != nil { return node, err } node.Add(n) // object lists can be optionally comma-delimited e.g. when a list of maps // is being expressed, so a comma is allowed here - it's simply consumed tok := p.scan() if tok.Type != token.COMMA { p.unscan() } } return node, nil } func (p *Parser) consumeComment() (comment *ast.Comment, endline int) { endline = p.tok.Pos.Line // count the endline if it's multiline comment, ie starting with /* if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' { // don't use range here - no need to decode Unicode code points for i := 0; i < len(p.tok.Text); i++ { if p.tok.Text[i] == '\n' { endline++ } } } comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text} p.tok = p.sc.Scan() return } func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) { var list []*ast.Comment endline = p.tok.Pos.Line for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n { var comment *ast.Comment comment, endline = p.consumeComment() list = append(list, comment) } // add comment group to the comments list comments = &ast.CommentGroup{List: list} p.comments = append(p.comments, comments) return } // objectItem parses a single object item func (p *Parser) objectItem() (*ast.ObjectItem, error) { defer un(trace(p, "ParseObjectItem")) keys, err := p.objectKey() if len(keys) > 0 && err == errEofToken { // We ignore eof token here since it is an error if we didn't // receive a value (but we did receive a key) for the item. err = nil } if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE { // This is a strange boolean statement, but what it means is: // We have keys with no value, and we're likely in an object // (since RBrace ends an object). For this, we set err to nil so // we continue and get the error below of having the wrong value // type. err = nil // Reset the token type so we don't think it completed fine. See // objectType which uses p.tok.Type to check if we're done with // the object. p.tok.Type = token.EOF } if err != nil { return nil, err } o := &ast.ObjectItem{ Keys: keys, } if p.leadComment != nil { o.LeadComment = p.leadComment p.leadComment = nil } switch p.tok.Type { case token.ASSIGN: o.Assign = p.tok.Pos o.Val, err = p.object() if err != nil { return nil, err } case token.LBRACE: o.Val, err = p.objectType() if err != nil { return nil, err } default: keyStr := make([]string, 0, len(keys)) for _, k := range keys { keyStr = append(keyStr, k.Token.Text) } return nil, fmt.Errorf( "key '%s' expected start of object ('{') or assignment ('=')", strings.Join(keyStr, " ")) } // do a look-ahead for line comment p.scan() if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil { o.LineComment = p.lineComment p.lineComment = nil } p.unscan() return o, nil } // objectKey parses an object key and returns a ObjectKey AST func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { keyCount := 0 keys := make([]*ast.ObjectKey, 0) for { tok := p.scan() switch tok.Type { case token.EOF: // It is very important to also return the keys here as well as // the error. This is because we need to be able to tell if we // did parse keys prior to finding the EOF, or if we just found // a bare EOF. return keys, errEofToken case token.ASSIGN: // assignment or object only, but not nested objects. this is not // allowed: `foo bar = {}` if keyCount > 1 { return nil, &PosError{ Pos: p.tok.Pos, Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type), } } if keyCount == 0 { return nil, &PosError{ Pos: p.tok.Pos, Err: errors.New("no object keys found!"), } } return keys, nil case token.LBRACE: var err error // If we have no keys, then it is a syntax error. i.e. {{}} is not // allowed. if len(keys) == 0 { err = &PosError{ Pos: p.tok.Pos, Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type), } } // object return keys, err case token.IDENT, token.STRING: keyCount++ keys = append(keys, &ast.ObjectKey{Token: p.tok}) case token.ILLEGAL: fmt.Println("illegal") default: return keys, &PosError{ Pos: p.tok.Pos, Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type), } } } } // object parses any type of object, such as number, bool, string, object or // list. func (p *Parser) object() (ast.Node, error) { defer un(trace(p, "ParseType")) tok := p.scan() switch tok.Type { case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC: return p.literalType() case token.LBRACE: return p.objectType() case token.LBRACK: return p.listType() case token.COMMENT: // implement comment case token.EOF: return nil, errEofToken } return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf("Unknown token: %+v", tok), } } // objectType parses an object type and returns a ObjectType AST func (p *Parser) objectType() (*ast.ObjectType, error) { defer un(trace(p, "ParseObjectType")) // we assume that the currently scanned token is a LBRACE o := &ast.ObjectType{ Lbrace: p.tok.Pos, } l, err := p.objectList() // if we hit RBRACE, we are good to go (means we parsed all Items), if it's // not a RBRACE, it's an syntax error and we just return it. if err != nil && p.tok.Type != token.RBRACE { return nil, err } // If there is no error, we should be at a RBRACE to end the object if p.tok.Type != token.RBRACE { return nil, fmt.Errorf("object expected closing RBRACE got: %s", p.tok.Type) } o.List = l o.Rbrace = p.tok.Pos // advanced via parseObjectList return o, nil } // listType parses a list type and returns a ListType AST func (p *Parser) listType() (*ast.ListType, error) { defer un(trace(p, "ParseListType")) // we assume that the currently scanned token is a LBRACK l := &ast.ListType{ Lbrack: p.tok.Pos, } needComma := false for { tok := p.scan() if needComma { switch tok.Type { case token.COMMA, token.RBRACK: default: return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf( "error parsing list, expected comma or list end, got: %s", tok.Type), } } } switch tok.Type { case token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC: node, err := p.literalType() if err != nil { return nil, err } l.Add(node) needComma = true case token.COMMA: // get next list item or we are at the end // do a look-ahead for line comment p.scan() if p.lineComment != nil && len(l.List) > 0 { lit, ok := l.List[len(l.List)-1].(*ast.LiteralType) if ok { lit.LineComment = p.lineComment l.List[len(l.List)-1] = lit p.lineComment = nil } } p.unscan() needComma = false continue case token.LBRACE: // Looks like a nested object, so parse it out node, err := p.objectType() if err != nil { return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf( "error while trying to parse object within list: %s", err), } } l.Add(node) needComma = true case token.BOOL: // TODO(arslan) should we support? not supported by HCL yet case token.LBRACK: // TODO(arslan) should we support nested lists? Even though it's // written in README of HCL, it's not a part of the grammar // (not defined in parse.y) case token.RBRACK: // finished l.Rbrack = p.tok.Pos return l, nil default: return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf("unexpected token while parsing list: %s", tok.Type), } } } } // literalType parses a literal type and returns a LiteralType AST func (p *Parser) literalType() (*ast.LiteralType, error) { defer un(trace(p, "ParseLiteral")) return &ast.LiteralType{ Token: p.tok, }, nil } // scan returns the next token from the underlying scanner. If a token has // been unscanned then read that instead. In the process, it collects any // comment groups encountered, and remembers the last lead and line comments. func (p *Parser) scan() token.Token { // If we have a token on the buffer, then return it. if p.n != 0 { p.n = 0 return p.tok } // Otherwise read the next token from the scanner and Save it to the buffer // in case we unscan later. prev := p.tok p.tok = p.sc.Scan() if p.tok.Type == token.COMMENT { var comment *ast.CommentGroup var endline int // fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n", // p.tok.Pos.Line, prev.Pos.Line, endline) if p.tok.Pos.Line == prev.Pos.Line { // The comment is on same line as the previous token; it // cannot be a lead comment but may be a line comment. comment, endline = p.consumeCommentGroup(0) if p.tok.Pos.Line != endline { // The next token is on a different line, thus // the last comment group is a line comment. p.lineComment = comment } } // consume successor comments, if any endline = -1 for p.tok.Type == token.COMMENT { comment, endline = p.consumeCommentGroup(1) } if endline+1 == p.tok.Pos.Line && p.tok.Type != token.RBRACE { switch p.tok.Type { case token.RBRACE, token.RBRACK: // Do not count for these cases default: // The next token is following on the line immediately after the // comment group, thus the last comment group is a lead comment. p.leadComment = comment } } } return p.tok } // unscan pushes the previously read token back onto the buffer. func (p *Parser) unscan() { p.n = 1 } // ---------------------------------------------------------------------------- // Parsing support func (p *Parser) printTrace(a ...interface{}) { if !p.enableTrace { return } const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " const n = len(dots) fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) i := 2 * p.indent for i > n { fmt.Print(dots) i -= n } // i <= n fmt.Print(dots[0:i]) fmt.Println(a...) } func trace(p *Parser, msg string) *Parser { p.printTrace(msg, "(") p.indent++ return p } // Usage pattern: defer un(trace(p, "...")) func un(p *Parser) { p.indent-- p.printTrace(")") } ================================================ FILE: vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go ================================================ // Package scanner implements a scanner for HCL (HashiCorp Configuration // Language) source text. package scanner import ( "bytes" "fmt" "os" "regexp" "unicode" "unicode/utf8" "github.com/hashicorp/hcl/hcl/token" ) // eof represents a marker rune for the end of the reader. const eof = rune(0) // Scanner defines a lexical scanner type Scanner struct { buf *bytes.Buffer // Source buffer for advancing and scanning src []byte // Source buffer for immutable access // Source Position srcPos token.Pos // current position prevPos token.Pos // previous position, used for peek() method lastCharLen int // length of last character in bytes lastLineLen int // length of last line in characters (for correct column reporting) tokStart int // token text start position tokEnd int // token text end position // Error is called for each error encountered. If no Error // function is set, the error is reported to os.Stderr. Error func(pos token.Pos, msg string) // ErrorCount is incremented by one for each error encountered. ErrorCount int // tokPos is the start position of most recently scanned token; set by // Scan. The Filename field is always left untouched by the Scanner. If // an error is reported (via Error) and Position is invalid, the scanner is // not inside a token. tokPos token.Pos } // New creates and initializes a new instance of Scanner using src as // its source content. func New(src []byte) *Scanner { // even though we accept a src, we read from a io.Reader compatible type // (*bytes.Buffer). So in the future we might easily change it to streaming // read. b := bytes.NewBuffer(src) s := &Scanner{ buf: b, src: src, } // srcPosition always starts with 1 s.srcPos.Line = 1 return s } // next reads the next rune from the bufferred reader. Returns the rune(0) if // an error occurs (or io.EOF is returned). func (s *Scanner) next() rune { ch, size, err := s.buf.ReadRune() if err != nil { // advance for error reporting s.srcPos.Column++ s.srcPos.Offset += size s.lastCharLen = size return eof } if ch == utf8.RuneError && size == 1 { s.srcPos.Column++ s.srcPos.Offset += size s.lastCharLen = size s.err("illegal UTF-8 encoding") return ch } // remember last position s.prevPos = s.srcPos s.srcPos.Column++ s.lastCharLen = size s.srcPos.Offset += size if ch == '\n' { s.srcPos.Line++ s.lastLineLen = s.srcPos.Column s.srcPos.Column = 0 } // debug // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) return ch } // unread unreads the previous read Rune and updates the source position func (s *Scanner) unread() { if err := s.buf.UnreadRune(); err != nil { panic(err) // this is user fault, we should catch it } s.srcPos = s.prevPos // put back last position } // peek returns the next rune without advancing the reader. func (s *Scanner) peek() rune { peek, _, err := s.buf.ReadRune() if err != nil { return eof } s.buf.UnreadRune() return peek } // Scan scans the next token and returns the token. func (s *Scanner) Scan() token.Token { ch := s.next() // skip white space for isWhitespace(ch) { ch = s.next() } var tok token.Type // token text markings s.tokStart = s.srcPos.Offset - s.lastCharLen // token position, initial next() is moving the offset by one(size of rune // actually), though we are interested with the starting point s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen if s.srcPos.Column > 0 { // common case: last character was not a '\n' s.tokPos.Line = s.srcPos.Line s.tokPos.Column = s.srcPos.Column } else { // last character was a '\n' // (we cannot be at the beginning of the source // since we have called next() at least once) s.tokPos.Line = s.srcPos.Line - 1 s.tokPos.Column = s.lastLineLen } switch { case isLetter(ch): tok = token.IDENT lit := s.scanIdentifier() if lit == "true" || lit == "false" { tok = token.BOOL } case isDecimal(ch): tok = s.scanNumber(ch) default: switch ch { case eof: tok = token.EOF case '"': tok = token.STRING s.scanString() case '#', '/': tok = token.COMMENT s.scanComment(ch) case '.': tok = token.PERIOD ch = s.peek() if isDecimal(ch) { tok = token.FLOAT ch = s.scanMantissa(ch) ch = s.scanExponent(ch) } case '<': tok = token.HEREDOC s.scanHeredoc() case '[': tok = token.LBRACK case ']': tok = token.RBRACK case '{': tok = token.LBRACE case '}': tok = token.RBRACE case ',': tok = token.COMMA case '=': tok = token.ASSIGN case '+': tok = token.ADD case '-': if isDecimal(s.peek()) { ch := s.next() tok = s.scanNumber(ch) } else { tok = token.SUB } default: s.err("illegal char") } } // finish token ending s.tokEnd = s.srcPos.Offset // create token literal var tokenText string if s.tokStart >= 0 { tokenText = string(s.src[s.tokStart:s.tokEnd]) } s.tokStart = s.tokEnd // ensure idempotency of tokenText() call return token.Token{ Type: tok, Pos: s.tokPos, Text: tokenText, } } func (s *Scanner) scanComment(ch rune) { // single line comments if ch == '#' || (ch == '/' && s.peek() != '*') { if ch == '/' && s.peek() != '/' { s.err("expected '/' for comment") return } ch = s.next() for ch != '\n' && ch >= 0 && ch != eof { ch = s.next() } if ch != eof && ch >= 0 { s.unread() } return } // be sure we get the character after /* This allows us to find comment's // that are not erminated if ch == '/' { s.next() ch = s.next() // read character after "/*" } // look for /* - style comments for { if ch < 0 || ch == eof { s.err("comment not terminated") break } ch0 := ch ch = s.next() if ch0 == '*' && ch == '/' { break } } } // scanNumber scans a HCL number definition starting with the given rune func (s *Scanner) scanNumber(ch rune) token.Type { if ch == '0' { // check for hexadecimal, octal or float ch = s.next() if ch == 'x' || ch == 'X' { // hexadecimal ch = s.next() found := false for isHexadecimal(ch) { ch = s.next() found = true } if !found { s.err("illegal hexadecimal number") } if ch != eof { s.unread() } return token.NUMBER } // now it's either something like: 0421(octal) or 0.1231(float) illegalOctal := false for isDecimal(ch) { ch = s.next() if ch == '8' || ch == '9' { // this is just a possibility. For example 0159 is illegal, but // 0159.23 is valid. So we mark a possible illegal octal. If // the next character is not a period, we'll print the error. illegalOctal = true } } if ch == 'e' || ch == 'E' { ch = s.scanExponent(ch) return token.FLOAT } if ch == '.' { ch = s.scanFraction(ch) if ch == 'e' || ch == 'E' { ch = s.next() ch = s.scanExponent(ch) } return token.FLOAT } if illegalOctal { s.err("illegal octal number") } if ch != eof { s.unread() } return token.NUMBER } s.scanMantissa(ch) ch = s.next() // seek forward if ch == 'e' || ch == 'E' { ch = s.scanExponent(ch) return token.FLOAT } if ch == '.' { ch = s.scanFraction(ch) if ch == 'e' || ch == 'E' { ch = s.next() ch = s.scanExponent(ch) } return token.FLOAT } if ch != eof { s.unread() } return token.NUMBER } // scanMantissa scans the mantissa begining from the rune. It returns the next // non decimal rune. It's used to determine wheter it's a fraction or exponent. func (s *Scanner) scanMantissa(ch rune) rune { scanned := false for isDecimal(ch) { ch = s.next() scanned = true } if scanned && ch != eof { s.unread() } return ch } // scanFraction scans the fraction after the '.' rune func (s *Scanner) scanFraction(ch rune) rune { if ch == '.' { ch = s.peek() // we peek just to see if we can move forward ch = s.scanMantissa(ch) } return ch } // scanExponent scans the remaining parts of an exponent after the 'e' or 'E' // rune. func (s *Scanner) scanExponent(ch rune) rune { if ch == 'e' || ch == 'E' { ch = s.next() if ch == '-' || ch == '+' { ch = s.next() } ch = s.scanMantissa(ch) } return ch } // scanHeredoc scans a heredoc string func (s *Scanner) scanHeredoc() { // Scan the second '<' in example: '<= len(identBytes) && identRegexp.Match(s.src[lineStart:s.srcPos.Offset-s.lastCharLen]) { break } // Not an anchor match, record the start of a new line lineStart = s.srcPos.Offset } if ch == eof { s.err("heredoc not terminated") return } } return } // scanString scans a quoted string func (s *Scanner) scanString() { braces := 0 for { // '"' opening already consumed // read character after quote ch := s.next() if ch < 0 || ch == eof { s.err("literal not terminated") return } if ch == '"' && braces == 0 { break } // If we're going into a ${} then we can ignore quotes for awhile if braces == 0 && ch == '$' && s.peek() == '{' { braces++ s.next() } else if braces > 0 && ch == '{' { braces++ } if braces > 0 && ch == '}' { braces-- } if ch == '\\' { s.scanEscape() } } return } // scanEscape scans an escape sequence func (s *Scanner) scanEscape() rune { // http://en.cppreference.com/w/cpp/language/escape ch := s.next() // read character after '/' switch ch { case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': // nothing to do case '0', '1', '2', '3', '4', '5', '6', '7': // octal notation ch = s.scanDigits(ch, 8, 3) case 'x': // hexademical notation ch = s.scanDigits(s.next(), 16, 2) case 'u': // universal character name ch = s.scanDigits(s.next(), 16, 4) case 'U': // universal character name ch = s.scanDigits(s.next(), 16, 8) default: s.err("illegal char escape") } return ch } // scanDigits scans a rune with the given base for n times. For example an // octal notation \184 would yield in scanDigits(ch, 8, 3) func (s *Scanner) scanDigits(ch rune, base, n int) rune { start := n for n > 0 && digitVal(ch) < base { ch = s.next() if ch == eof { // If we see an EOF, we halt any more scanning of digits // immediately. break } n-- } if n > 0 { s.err("illegal char escape") } if n != start { // we scanned all digits, put the last non digit char back, // only if we read anything at all s.unread() } return ch } // scanIdentifier scans an identifier and returns the literal string func (s *Scanner) scanIdentifier() string { offs := s.srcPos.Offset - s.lastCharLen ch := s.next() for isLetter(ch) || isDigit(ch) || ch == '-' || ch == '.' { ch = s.next() } if ch != eof { s.unread() // we got identifier, put back latest char } return string(s.src[offs:s.srcPos.Offset]) } // recentPosition returns the position of the character immediately after the // character or token returned by the last call to Scan. func (s *Scanner) recentPosition() (pos token.Pos) { pos.Offset = s.srcPos.Offset - s.lastCharLen switch { case s.srcPos.Column > 0: // common case: last character was not a '\n' pos.Line = s.srcPos.Line pos.Column = s.srcPos.Column case s.lastLineLen > 0: // last character was a '\n' // (we cannot be at the beginning of the source // since we have called next() at least once) pos.Line = s.srcPos.Line - 1 pos.Column = s.lastLineLen default: // at the beginning of the source pos.Line = 1 pos.Column = 1 } return } // err prints the error of any scanning to s.Error function. If the function is // not defined, by default it prints them to os.Stderr func (s *Scanner) err(msg string) { s.ErrorCount++ pos := s.recentPosition() if s.Error != nil { s.Error(pos, msg) return } fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) } // isHexadecimal returns true if the given rune is a letter func isLetter(ch rune) bool { return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) } // isDigit returns true if the given rune is a decimal digit func isDigit(ch rune) bool { return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) } // isDecimal returns true if the given rune is a decimal number func isDecimal(ch rune) bool { return '0' <= ch && ch <= '9' } // isHexadecimal returns true if the given rune is an hexadecimal number func isHexadecimal(ch rune) bool { return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' } // isWhitespace returns true if the rune is a space, tab, newline or carriage return func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } // digitVal returns the integer value of a given octal,decimal or hexadecimal rune func digitVal(ch rune) int { switch { case '0' <= ch && ch <= '9': return int(ch - '0') case 'a' <= ch && ch <= 'f': return int(ch - 'a' + 10) case 'A' <= ch && ch <= 'F': return int(ch - 'A' + 10) } return 16 // larger than any legal digit val } ================================================ FILE: vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go ================================================ package strconv import ( "errors" "unicode/utf8" ) // ErrSyntax indicates that a value does not have the right syntax for the target type. var ErrSyntax = errors.New("invalid syntax") // Unquote interprets s as a single-quoted, double-quoted, // or backquoted Go string literal, returning the string value // that s quotes. (If s is single-quoted, it would be a Go // character literal; Unquote returns the corresponding // one-character string.) func Unquote(s string) (t string, err error) { n := len(s) if n < 2 { return "", ErrSyntax } quote := s[0] if quote != s[n-1] { return "", ErrSyntax } s = s[1 : n-1] if quote != '"' { return "", ErrSyntax } // Is it trivial? Avoid allocation. if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') { switch quote { case '"': return s, nil case '\'': r, size := utf8.DecodeRuneInString(s) if size == len(s) && (r != utf8.RuneError || size != 1) { return s, nil } } } var runeTmp [utf8.UTFMax]byte buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. for len(s) > 0 { // If we're starting a '${}' then let it through un-unquoted. // Specifically: we don't unquote any characters within the `${}` // section, except for escaped backslashes, which we handle specifically. if s[0] == '$' && len(s) > 1 && s[1] == '{' { buf = append(buf, '$', '{') s = s[2:] // Continue reading until we find the closing brace, copying as-is braces := 1 for len(s) > 0 && braces > 0 { r, size := utf8.DecodeRuneInString(s) if r == utf8.RuneError { return "", ErrSyntax } s = s[size:] // We special case escaped backslashes in interpolations, converting // them to their unescaped equivalents. if r == '\\' { q, _ := utf8.DecodeRuneInString(s) switch q { case '\\': continue } } n := utf8.EncodeRune(runeTmp[:], r) buf = append(buf, runeTmp[:n]...) switch r { case '{': braces++ case '}': braces-- } } if braces != 0 { return "", ErrSyntax } if len(s) == 0 { // If there's no string left, we're done! break } else { // If there's more left, we need to pop back up to the top of the loop // in case there's another interpolation in this string. continue } } c, multibyte, ss, err := unquoteChar(s, quote) if err != nil { return "", err } s = ss if c < utf8.RuneSelf || !multibyte { buf = append(buf, byte(c)) } else { n := utf8.EncodeRune(runeTmp[:], c) buf = append(buf, runeTmp[:n]...) } if quote == '\'' && len(s) != 0 { // single-quoted must be single character return "", ErrSyntax } } return string(buf), nil } // contains reports whether the string contains the byte c. func contains(s string, c byte) bool { for i := 0; i < len(s); i++ { if s[i] == c { return true } } return false } func unhex(b byte) (v rune, ok bool) { c := rune(b) switch { case '0' <= c && c <= '9': return c - '0', true case 'a' <= c && c <= 'f': return c - 'a' + 10, true case 'A' <= c && c <= 'F': return c - 'A' + 10, true } return } func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { // easy cases switch c := s[0]; { case c == quote && (quote == '\'' || quote == '"'): err = ErrSyntax return case c >= utf8.RuneSelf: r, size := utf8.DecodeRuneInString(s) return r, true, s[size:], nil case c != '\\': return rune(s[0]), false, s[1:], nil } // hard case: c is backslash if len(s) <= 1 { err = ErrSyntax return } c := s[1] s = s[2:] switch c { case 'a': value = '\a' case 'b': value = '\b' case 'f': value = '\f' case 'n': value = '\n' case 'r': value = '\r' case 't': value = '\t' case 'v': value = '\v' case 'x', 'u', 'U': n := 0 switch c { case 'x': n = 2 case 'u': n = 4 case 'U': n = 8 } var v rune if len(s) < n { err = ErrSyntax return } for j := 0; j < n; j++ { x, ok := unhex(s[j]) if !ok { err = ErrSyntax return } v = v<<4 | x } s = s[n:] if c == 'x' { // single-byte string, possibly not UTF-8 value = v break } if v > utf8.MaxRune { err = ErrSyntax return } value = v multibyte = true case '0', '1', '2', '3', '4', '5', '6', '7': v := rune(c) - '0' if len(s) < 2 { err = ErrSyntax return } for j := 0; j < 2; j++ { // one digit already; two more x := rune(s[j]) - '0' if x < 0 || x > 7 { err = ErrSyntax return } v = (v << 3) | x } s = s[2:] if v > 255 { err = ErrSyntax return } value = v case '\\': value = '\\' case '\'', '"': if c != quote { err = ErrSyntax return } value = rune(c) default: err = ErrSyntax return } tail = s return } ================================================ FILE: vendor/github.com/hashicorp/hcl/hcl/token/position.go ================================================ package token import "fmt" // Pos describes an arbitrary source position // including the file, line, and column location. // A Position is valid if the line number is > 0. type Pos struct { Filename string // filename, if any Offset int // offset, starting at 0 Line int // line number, starting at 1 Column int // column number, starting at 1 (character count) } // IsValid returns true if the position is valid. func (p *Pos) IsValid() bool { return p.Line > 0 } // String returns a string in one of several forms: // // file:line:column valid position with file name // line:column valid position without file name // file invalid position with file name // - invalid position without file name func (p Pos) String() string { s := p.Filename if p.IsValid() { if s != "" { s += ":" } s += fmt.Sprintf("%d:%d", p.Line, p.Column) } if s == "" { s = "-" } return s } // Before reports whether the position p is before u. func (p Pos) Before(u Pos) bool { return u.Offset > p.Offset || u.Line > p.Line } // After reports whether the position p is after u. func (p Pos) After(u Pos) bool { return u.Offset < p.Offset || u.Line < p.Line } ================================================ FILE: vendor/github.com/hashicorp/hcl/hcl/token/token.go ================================================ // Package token defines constants representing the lexical tokens for HCL // (HashiCorp Configuration Language) package token import ( "fmt" "strconv" "strings" hclstrconv "github.com/hashicorp/hcl/hcl/strconv" ) // Token defines a single HCL token which can be obtained via the Scanner type Token struct { Type Type Pos Pos Text string JSON bool } // Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) type Type int const ( // Special tokens ILLEGAL Type = iota EOF COMMENT identifier_beg IDENT // literals literal_beg NUMBER // 12345 FLOAT // 123.45 BOOL // true,false STRING // "abc" HEREDOC // < 0 { // Pop the current item n := len(frontier) item := frontier[n-1] frontier = frontier[:n-1] switch v := item.Val.(type) { case *ast.ObjectType: items, frontier = flattenObjectType(v, item, items, frontier) case *ast.ListType: items, frontier = flattenListType(v, item, items, frontier) default: items = append(items, item) } } // Reverse the list since the frontier model runs things backwards for i := len(items)/2 - 1; i >= 0; i-- { opp := len(items) - 1 - i items[i], items[opp] = items[opp], items[i] } // Done! Set the original items list.Items = items return n, true }) } func flattenListType( ot *ast.ListType, item *ast.ObjectItem, items []*ast.ObjectItem, frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { // All the elements of this object must also be objects! for _, subitem := range ot.List { if _, ok := subitem.(*ast.ObjectType); !ok { items = append(items, item) return items, frontier } } // Great! We have a match go through all the items and flatten for _, elem := range ot.List { // Add it to the frontier so that we can recurse frontier = append(frontier, &ast.ObjectItem{ Keys: item.Keys, Assign: item.Assign, Val: elem, LeadComment: item.LeadComment, LineComment: item.LineComment, }) } return items, frontier } func flattenObjectType( ot *ast.ObjectType, item *ast.ObjectItem, items []*ast.ObjectItem, frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { // If the list has no items we do not have to flatten anything if ot.List.Items == nil { items = append(items, item) return items, frontier } // All the elements of this object must also be objects! for _, subitem := range ot.List.Items { if _, ok := subitem.Val.(*ast.ObjectType); !ok { items = append(items, item) return items, frontier } } // Great! We have a match go through all the items and flatten for _, subitem := range ot.List.Items { // Copy the new key keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys)) copy(keys, item.Keys) copy(keys[len(item.Keys):], subitem.Keys) // Add it to the frontier so that we can recurse frontier = append(frontier, &ast.ObjectItem{ Keys: keys, Assign: item.Assign, Val: subitem.Val, LeadComment: item.LeadComment, LineComment: item.LineComment, }) } return items, frontier } ================================================ FILE: vendor/github.com/hashicorp/hcl/json/parser/parser.go ================================================ package parser import ( "errors" "fmt" "github.com/hashicorp/hcl/hcl/ast" "github.com/hashicorp/hcl/json/scanner" "github.com/hashicorp/hcl/json/token" ) type Parser struct { sc *scanner.Scanner // Last read token tok token.Token commaPrev token.Token enableTrace bool indent int n int // buffer size (max = 1) } func newParser(src []byte) *Parser { return &Parser{ sc: scanner.New(src), } } // Parse returns the fully parsed source and returns the abstract syntax tree. func Parse(src []byte) (*ast.File, error) { p := newParser(src) return p.Parse() } var errEofToken = errors.New("EOF token found") // Parse returns the fully parsed source and returns the abstract syntax tree. func (p *Parser) Parse() (*ast.File, error) { f := &ast.File{} var err, scerr error p.sc.Error = func(pos token.Pos, msg string) { scerr = fmt.Errorf("%s: %s", pos, msg) } // The root must be an object in JSON object, err := p.object() if scerr != nil { return nil, scerr } if err != nil { return nil, err } // We make our final node an object list so it is more HCL compatible f.Node = object.List // Flatten it, which finds patterns and turns them into more HCL-like // AST trees. flattenObjects(f.Node) return f, nil } func (p *Parser) objectList() (*ast.ObjectList, error) { defer un(trace(p, "ParseObjectList")) node := &ast.ObjectList{} for { n, err := p.objectItem() if err == errEofToken { break // we are finished } // we don't return a nil node, because might want to use already // collected items. if err != nil { return node, err } node.Add(n) // Check for a followup comma. If it isn't a comma, then we're done if tok := p.scan(); tok.Type != token.COMMA { break } } return node, nil } // objectItem parses a single object item func (p *Parser) objectItem() (*ast.ObjectItem, error) { defer un(trace(p, "ParseObjectItem")) keys, err := p.objectKey() if err != nil { return nil, err } o := &ast.ObjectItem{ Keys: keys, } switch p.tok.Type { case token.COLON: o.Val, err = p.objectValue() if err != nil { return nil, err } } return o, nil } // objectKey parses an object key and returns a ObjectKey AST func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { keyCount := 0 keys := make([]*ast.ObjectKey, 0) for { tok := p.scan() switch tok.Type { case token.EOF: return nil, errEofToken case token.STRING: keyCount++ keys = append(keys, &ast.ObjectKey{ Token: p.tok.HCLToken(), }) case token.COLON: // If we have a zero keycount it means that we never got // an object key, i.e. `{ :`. This is a syntax error. if keyCount == 0 { return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) } // Done return keys, nil case token.ILLEGAL: fmt.Println("illegal") default: return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) } } } // object parses any type of object, such as number, bool, string, object or // list. func (p *Parser) objectValue() (ast.Node, error) { defer un(trace(p, "ParseObjectValue")) tok := p.scan() switch tok.Type { case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING: return p.literalType() case token.LBRACE: return p.objectType() case token.LBRACK: return p.listType() case token.EOF: return nil, errEofToken } return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok) } // object parses any type of object, such as number, bool, string, object or // list. func (p *Parser) object() (*ast.ObjectType, error) { defer un(trace(p, "ParseType")) tok := p.scan() switch tok.Type { case token.LBRACE: return p.objectType() case token.EOF: return nil, errEofToken } return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok) } // objectType parses an object type and returns a ObjectType AST func (p *Parser) objectType() (*ast.ObjectType, error) { defer un(trace(p, "ParseObjectType")) // we assume that the currently scanned token is a LBRACE o := &ast.ObjectType{} l, err := p.objectList() // if we hit RBRACE, we are good to go (means we parsed all Items), if it's // not a RBRACE, it's an syntax error and we just return it. if err != nil && p.tok.Type != token.RBRACE { return nil, err } o.List = l return o, nil } // listType parses a list type and returns a ListType AST func (p *Parser) listType() (*ast.ListType, error) { defer un(trace(p, "ParseListType")) // we assume that the currently scanned token is a LBRACK l := &ast.ListType{} for { tok := p.scan() switch tok.Type { case token.NUMBER, token.FLOAT, token.STRING: node, err := p.literalType() if err != nil { return nil, err } l.Add(node) case token.COMMA: continue case token.LBRACE: node, err := p.objectType() if err != nil { return nil, err } l.Add(node) case token.BOOL: // TODO(arslan) should we support? not supported by HCL yet case token.LBRACK: // TODO(arslan) should we support nested lists? Even though it's // written in README of HCL, it's not a part of the grammar // (not defined in parse.y) case token.RBRACK: // finished return l, nil default: return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type) } } } // literalType parses a literal type and returns a LiteralType AST func (p *Parser) literalType() (*ast.LiteralType, error) { defer un(trace(p, "ParseLiteral")) return &ast.LiteralType{ Token: p.tok.HCLToken(), }, nil } // scan returns the next token from the underlying scanner. If a token has // been unscanned then read that instead. func (p *Parser) scan() token.Token { // If we have a token on the buffer, then return it. if p.n != 0 { p.n = 0 return p.tok } p.tok = p.sc.Scan() return p.tok } // unscan pushes the previously read token back onto the buffer. func (p *Parser) unscan() { p.n = 1 } // ---------------------------------------------------------------------------- // Parsing support func (p *Parser) printTrace(a ...interface{}) { if !p.enableTrace { return } const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " const n = len(dots) fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) i := 2 * p.indent for i > n { fmt.Print(dots) i -= n } // i <= n fmt.Print(dots[0:i]) fmt.Println(a...) } func trace(p *Parser, msg string) *Parser { p.printTrace(msg, "(") p.indent++ return p } // Usage pattern: defer un(trace(p, "...")) func un(p *Parser) { p.indent-- p.printTrace(")") } ================================================ FILE: vendor/github.com/hashicorp/hcl/json/scanner/scanner.go ================================================ package scanner import ( "bytes" "fmt" "os" "unicode" "unicode/utf8" "github.com/hashicorp/hcl/json/token" ) // eof represents a marker rune for the end of the reader. const eof = rune(0) // Scanner defines a lexical scanner type Scanner struct { buf *bytes.Buffer // Source buffer for advancing and scanning src []byte // Source buffer for immutable access // Source Position srcPos token.Pos // current position prevPos token.Pos // previous position, used for peek() method lastCharLen int // length of last character in bytes lastLineLen int // length of last line in characters (for correct column reporting) tokStart int // token text start position tokEnd int // token text end position // Error is called for each error encountered. If no Error // function is set, the error is reported to os.Stderr. Error func(pos token.Pos, msg string) // ErrorCount is incremented by one for each error encountered. ErrorCount int // tokPos is the start position of most recently scanned token; set by // Scan. The Filename field is always left untouched by the Scanner. If // an error is reported (via Error) and Position is invalid, the scanner is // not inside a token. tokPos token.Pos } // New creates and initializes a new instance of Scanner using src as // its source content. func New(src []byte) *Scanner { // even though we accept a src, we read from a io.Reader compatible type // (*bytes.Buffer). So in the future we might easily change it to streaming // read. b := bytes.NewBuffer(src) s := &Scanner{ buf: b, src: src, } // srcPosition always starts with 1 s.srcPos.Line = 1 return s } // next reads the next rune from the bufferred reader. Returns the rune(0) if // an error occurs (or io.EOF is returned). func (s *Scanner) next() rune { ch, size, err := s.buf.ReadRune() if err != nil { // advance for error reporting s.srcPos.Column++ s.srcPos.Offset += size s.lastCharLen = size return eof } if ch == utf8.RuneError && size == 1 { s.srcPos.Column++ s.srcPos.Offset += size s.lastCharLen = size s.err("illegal UTF-8 encoding") return ch } // remember last position s.prevPos = s.srcPos s.srcPos.Column++ s.lastCharLen = size s.srcPos.Offset += size if ch == '\n' { s.srcPos.Line++ s.lastLineLen = s.srcPos.Column s.srcPos.Column = 0 } // debug // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) return ch } // unread unreads the previous read Rune and updates the source position func (s *Scanner) unread() { if err := s.buf.UnreadRune(); err != nil { panic(err) // this is user fault, we should catch it } s.srcPos = s.prevPos // put back last position } // peek returns the next rune without advancing the reader. func (s *Scanner) peek() rune { peek, _, err := s.buf.ReadRune() if err != nil { return eof } s.buf.UnreadRune() return peek } // Scan scans the next token and returns the token. func (s *Scanner) Scan() token.Token { ch := s.next() // skip white space for isWhitespace(ch) { ch = s.next() } var tok token.Type // token text markings s.tokStart = s.srcPos.Offset - s.lastCharLen // token position, initial next() is moving the offset by one(size of rune // actually), though we are interested with the starting point s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen if s.srcPos.Column > 0 { // common case: last character was not a '\n' s.tokPos.Line = s.srcPos.Line s.tokPos.Column = s.srcPos.Column } else { // last character was a '\n' // (we cannot be at the beginning of the source // since we have called next() at least once) s.tokPos.Line = s.srcPos.Line - 1 s.tokPos.Column = s.lastLineLen } switch { case isLetter(ch): lit := s.scanIdentifier() if lit == "true" || lit == "false" { tok = token.BOOL } else if lit == "null" { tok = token.NULL } else { s.err("illegal char") } case isDecimal(ch): tok = s.scanNumber(ch) default: switch ch { case eof: tok = token.EOF case '"': tok = token.STRING s.scanString() case '.': tok = token.PERIOD ch = s.peek() if isDecimal(ch) { tok = token.FLOAT ch = s.scanMantissa(ch) ch = s.scanExponent(ch) } case '[': tok = token.LBRACK case ']': tok = token.RBRACK case '{': tok = token.LBRACE case '}': tok = token.RBRACE case ',': tok = token.COMMA case ':': tok = token.COLON case '-': if isDecimal(s.peek()) { ch := s.next() tok = s.scanNumber(ch) } else { s.err("illegal char") } default: s.err("illegal char: " + string(ch)) } } // finish token ending s.tokEnd = s.srcPos.Offset // create token literal var tokenText string if s.tokStart >= 0 { tokenText = string(s.src[s.tokStart:s.tokEnd]) } s.tokStart = s.tokEnd // ensure idempotency of tokenText() call return token.Token{ Type: tok, Pos: s.tokPos, Text: tokenText, } } // scanNumber scans a HCL number definition starting with the given rune func (s *Scanner) scanNumber(ch rune) token.Type { zero := ch == '0' pos := s.srcPos s.scanMantissa(ch) ch = s.next() // seek forward if ch == 'e' || ch == 'E' { ch = s.scanExponent(ch) return token.FLOAT } if ch == '.' { ch = s.scanFraction(ch) if ch == 'e' || ch == 'E' { ch = s.next() ch = s.scanExponent(ch) } return token.FLOAT } if ch != eof { s.unread() } // If we have a larger number and this is zero, error if zero && pos != s.srcPos { s.err("numbers cannot start with 0") } return token.NUMBER } // scanMantissa scans the mantissa begining from the rune. It returns the next // non decimal rune. It's used to determine wheter it's a fraction or exponent. func (s *Scanner) scanMantissa(ch rune) rune { scanned := false for isDecimal(ch) { ch = s.next() scanned = true } if scanned && ch != eof { s.unread() } return ch } // scanFraction scans the fraction after the '.' rune func (s *Scanner) scanFraction(ch rune) rune { if ch == '.' { ch = s.peek() // we peek just to see if we can move forward ch = s.scanMantissa(ch) } return ch } // scanExponent scans the remaining parts of an exponent after the 'e' or 'E' // rune. func (s *Scanner) scanExponent(ch rune) rune { if ch == 'e' || ch == 'E' { ch = s.next() if ch == '-' || ch == '+' { ch = s.next() } ch = s.scanMantissa(ch) } return ch } // scanString scans a quoted string func (s *Scanner) scanString() { braces := 0 for { // '"' opening already consumed // read character after quote ch := s.next() if ch == '\n' || ch < 0 || ch == eof { s.err("literal not terminated") return } if ch == '"' { break } // If we're going into a ${} then we can ignore quotes for awhile if braces == 0 && ch == '$' && s.peek() == '{' { braces++ s.next() } else if braces > 0 && ch == '{' { braces++ } if braces > 0 && ch == '}' { braces-- } if ch == '\\' { s.scanEscape() } } return } // scanEscape scans an escape sequence func (s *Scanner) scanEscape() rune { // http://en.cppreference.com/w/cpp/language/escape ch := s.next() // read character after '/' switch ch { case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': // nothing to do case '0', '1', '2', '3', '4', '5', '6', '7': // octal notation ch = s.scanDigits(ch, 8, 3) case 'x': // hexademical notation ch = s.scanDigits(s.next(), 16, 2) case 'u': // universal character name ch = s.scanDigits(s.next(), 16, 4) case 'U': // universal character name ch = s.scanDigits(s.next(), 16, 8) default: s.err("illegal char escape") } return ch } // scanDigits scans a rune with the given base for n times. For example an // octal notation \184 would yield in scanDigits(ch, 8, 3) func (s *Scanner) scanDigits(ch rune, base, n int) rune { for n > 0 && digitVal(ch) < base { ch = s.next() n-- } if n > 0 { s.err("illegal char escape") } // we scanned all digits, put the last non digit char back s.unread() return ch } // scanIdentifier scans an identifier and returns the literal string func (s *Scanner) scanIdentifier() string { offs := s.srcPos.Offset - s.lastCharLen ch := s.next() for isLetter(ch) || isDigit(ch) || ch == '-' { ch = s.next() } if ch != eof { s.unread() // we got identifier, put back latest char } return string(s.src[offs:s.srcPos.Offset]) } // recentPosition returns the position of the character immediately after the // character or token returned by the last call to Scan. func (s *Scanner) recentPosition() (pos token.Pos) { pos.Offset = s.srcPos.Offset - s.lastCharLen switch { case s.srcPos.Column > 0: // common case: last character was not a '\n' pos.Line = s.srcPos.Line pos.Column = s.srcPos.Column case s.lastLineLen > 0: // last character was a '\n' // (we cannot be at the beginning of the source // since we have called next() at least once) pos.Line = s.srcPos.Line - 1 pos.Column = s.lastLineLen default: // at the beginning of the source pos.Line = 1 pos.Column = 1 } return } // err prints the error of any scanning to s.Error function. If the function is // not defined, by default it prints them to os.Stderr func (s *Scanner) err(msg string) { s.ErrorCount++ pos := s.recentPosition() if s.Error != nil { s.Error(pos, msg) return } fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) } // isHexadecimal returns true if the given rune is a letter func isLetter(ch rune) bool { return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) } // isHexadecimal returns true if the given rune is a decimal digit func isDigit(ch rune) bool { return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) } // isHexadecimal returns true if the given rune is a decimal number func isDecimal(ch rune) bool { return '0' <= ch && ch <= '9' } // isHexadecimal returns true if the given rune is an hexadecimal number func isHexadecimal(ch rune) bool { return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' } // isWhitespace returns true if the rune is a space, tab, newline or carriage return func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } // digitVal returns the integer value of a given octal,decimal or hexadecimal rune func digitVal(ch rune) int { switch { case '0' <= ch && ch <= '9': return int(ch - '0') case 'a' <= ch && ch <= 'f': return int(ch - 'a' + 10) case 'A' <= ch && ch <= 'F': return int(ch - 'A' + 10) } return 16 // larger than any legal digit val } ================================================ FILE: vendor/github.com/hashicorp/hcl/json/token/position.go ================================================ package token import "fmt" // Pos describes an arbitrary source position // including the file, line, and column location. // A Position is valid if the line number is > 0. type Pos struct { Filename string // filename, if any Offset int // offset, starting at 0 Line int // line number, starting at 1 Column int // column number, starting at 1 (character count) } // IsValid returns true if the position is valid. func (p *Pos) IsValid() bool { return p.Line > 0 } // String returns a string in one of several forms: // // file:line:column valid position with file name // line:column valid position without file name // file invalid position with file name // - invalid position without file name func (p Pos) String() string { s := p.Filename if p.IsValid() { if s != "" { s += ":" } s += fmt.Sprintf("%d:%d", p.Line, p.Column) } if s == "" { s = "-" } return s } // Before reports whether the position p is before u. func (p Pos) Before(u Pos) bool { return u.Offset > p.Offset || u.Line > p.Line } // After reports whether the position p is after u. func (p Pos) After(u Pos) bool { return u.Offset < p.Offset || u.Line < p.Line } ================================================ FILE: vendor/github.com/hashicorp/hcl/json/token/token.go ================================================ package token import ( "fmt" "strconv" hcltoken "github.com/hashicorp/hcl/hcl/token" ) // Token defines a single HCL token which can be obtained via the Scanner type Token struct { Type Type Pos Pos Text string } // Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) type Type int const ( // Special tokens ILLEGAL Type = iota EOF identifier_beg literal_beg NUMBER // 12345 FLOAT // 123.45 BOOL // true,false STRING // "abc" NULL // null literal_end identifier_end operator_beg LBRACK // [ LBRACE // { COMMA // , PERIOD // . COLON // : RBRACK // ] RBRACE // } operator_end ) var tokens = [...]string{ ILLEGAL: "ILLEGAL", EOF: "EOF", NUMBER: "NUMBER", FLOAT: "FLOAT", BOOL: "BOOL", STRING: "STRING", NULL: "NULL", LBRACK: "LBRACK", LBRACE: "LBRACE", COMMA: "COMMA", PERIOD: "PERIOD", COLON: "COLON", RBRACK: "RBRACK", RBRACE: "RBRACE", } // String returns the string corresponding to the token tok. func (t Type) String() string { s := "" if 0 <= t && t < Type(len(tokens)) { s = tokens[t] } if s == "" { s = "token(" + strconv.Itoa(int(t)) + ")" } return s } // IsIdentifier returns true for tokens corresponding to identifiers and basic // type literals; it returns false otherwise. func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end } // IsLiteral returns true for tokens corresponding to basic type literals; it // returns false otherwise. func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end } // IsOperator returns true for tokens corresponding to operators and // delimiters; it returns false otherwise. func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end } // String returns the token's literal text. Note that this is only // applicable for certain token types, such as token.IDENT, // token.STRING, etc.. func (t Token) String() string { return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text) } // HCLToken converts this token to an HCL token. // // The token type must be a literal type or this will panic. func (t Token) HCLToken() hcltoken.Token { switch t.Type { case BOOL: return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text} case FLOAT: return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text} case NULL: return hcltoken.Token{Type: hcltoken.STRING, Text: ""} case NUMBER: return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text} case STRING: return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true} default: panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type)) } } ================================================ FILE: vendor/github.com/hashicorp/hcl/lex.go ================================================ package hcl import ( "unicode" "unicode/utf8" ) type lexModeValue byte const ( lexModeUnknown lexModeValue = iota lexModeHcl lexModeJson ) // lexMode returns whether we're going to be parsing in JSON // mode or HCL mode. func lexMode(v []byte) lexModeValue { var ( r rune w int offset int ) for { r, w = utf8.DecodeRune(v[offset:]) offset += w if unicode.IsSpace(r) { continue } if r == '{' { return lexModeJson } break } return lexModeHcl } ================================================ FILE: vendor/github.com/hashicorp/hcl/parse.go ================================================ package hcl import ( "fmt" "github.com/hashicorp/hcl/hcl/ast" hclParser "github.com/hashicorp/hcl/hcl/parser" jsonParser "github.com/hashicorp/hcl/json/parser" ) // ParseBytes accepts as input byte slice and returns ast tree. // // Input can be either JSON or HCL func ParseBytes(in []byte) (*ast.File, error) { return parse(in) } // ParseString accepts input as a string and returns ast tree. func ParseString(input string) (*ast.File, error) { return parse([]byte(input)) } func parse(in []byte) (*ast.File, error) { switch lexMode(in) { case lexModeHcl: return hclParser.Parse(in) case lexModeJson: return jsonParser.Parse(in) } return nil, fmt.Errorf("unknown config format") } // Parse parses the given input and returns the root object. // // The input format can be either HCL or JSON. func Parse(input string) (*ast.File, error) { return parse([]byte(input)) } ================================================ FILE: vendor/github.com/jmespath/go-jmespath/LICENSE ================================================ Copyright 2015 James Saryerwinnie Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: vendor/github.com/jmespath/go-jmespath/Makefile ================================================ CMD = jpgo help: @echo "Please use \`make ' where is one of" @echo " test to run all the tests" @echo " build to build the library and jp executable" @echo " generate to run codegen" generate: go generate ./... build: rm -f $(CMD) go build ./... rm -f cmd/$(CMD)/$(CMD) && cd cmd/$(CMD)/ && go build ./... mv cmd/$(CMD)/$(CMD) . test: go test -v ./... check: go vet ./... @echo "golint ./..." @lint=`golint ./...`; \ lint=`echo "$$lint" | grep -v "astnodetype_string.go" | grep -v "toktype_string.go"`; \ echo "$$lint"; \ if [ "$$lint" != "" ]; then exit 1; fi htmlc: go test -coverprofile="/tmp/jpcov" && go tool cover -html="/tmp/jpcov" && unlink /tmp/jpcov buildfuzz: go-fuzz-build github.com/jmespath/go-jmespath/fuzz fuzz: buildfuzz go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/testdata bench: go test -bench . -cpuprofile cpu.out pprof-cpu: go tool pprof ./go-jmespath.test ./cpu.out ================================================ FILE: vendor/github.com/jmespath/go-jmespath/README.md ================================================ # go-jmespath - A JMESPath implementation in Go [![Build Status](https://img.shields.io/travis/jmespath/go-jmespath.svg)](https://travis-ci.org/jmespath/go-jmespath) See http://jmespath.org for more info. ================================================ FILE: vendor/github.com/jmespath/go-jmespath/api.go ================================================ package jmespath import "strconv" // JmesPath is the epresentation of a compiled JMES path query. A JmesPath is // safe for concurrent use by multiple goroutines. type JMESPath struct { ast ASTNode intr *treeInterpreter } // Compile parses a JMESPath expression and returns, if successful, a JMESPath // object that can be used to match against data. func Compile(expression string) (*JMESPath, error) { parser := NewParser() ast, err := parser.Parse(expression) if err != nil { return nil, err } jmespath := &JMESPath{ast: ast, intr: newInterpreter()} return jmespath, nil } // MustCompile is like Compile but panics if the expression cannot be parsed. // It simplifies safe initialization of global variables holding compiled // JMESPaths. func MustCompile(expression string) *JMESPath { jmespath, err := Compile(expression) if err != nil { panic(`jmespath: Compile(` + strconv.Quote(expression) + `): ` + err.Error()) } return jmespath } // Search evaluates a JMESPath expression against input data and returns the result. func (jp *JMESPath) Search(data interface{}) (interface{}, error) { return jp.intr.Execute(jp.ast, data) } // Search evaluates a JMESPath expression against input data and returns the result. func Search(expression string, data interface{}) (interface{}, error) { intr := newInterpreter() parser := NewParser() ast, err := parser.Parse(expression) if err != nil { return nil, err } return intr.Execute(ast, data) } ================================================ FILE: vendor/github.com/jmespath/go-jmespath/astnodetype_string.go ================================================ // generated by stringer -type astNodeType; DO NOT EDIT package jmespath import "fmt" const _astNodeType_name = "ASTEmptyASTComparatorASTCurrentNodeASTExpRefASTFunctionExpressionASTFieldASTFilterProjectionASTFlattenASTIdentityASTIndexASTIndexExpressionASTKeyValPairASTLiteralASTMultiSelectHashASTMultiSelectListASTOrExpressionASTAndExpressionASTNotExpressionASTPipeASTProjectionASTSubexpressionASTSliceASTValueProjection" var _astNodeType_index = [...]uint16{0, 8, 21, 35, 44, 65, 73, 92, 102, 113, 121, 139, 152, 162, 180, 198, 213, 229, 245, 252, 265, 281, 289, 307} func (i astNodeType) String() string { if i < 0 || i >= astNodeType(len(_astNodeType_index)-1) { return fmt.Sprintf("astNodeType(%d)", i) } return _astNodeType_name[_astNodeType_index[i]:_astNodeType_index[i+1]] } ================================================ FILE: vendor/github.com/jmespath/go-jmespath/functions.go ================================================ package jmespath import ( "encoding/json" "errors" "fmt" "math" "reflect" "sort" "strconv" "strings" "unicode/utf8" ) type jpFunction func(arguments []interface{}) (interface{}, error) type jpType string const ( jpUnknown jpType = "unknown" jpNumber jpType = "number" jpString jpType = "string" jpArray jpType = "array" jpObject jpType = "object" jpArrayNumber jpType = "array[number]" jpArrayString jpType = "array[string]" jpExpref jpType = "expref" jpAny jpType = "any" ) type functionEntry struct { name string arguments []argSpec handler jpFunction hasExpRef bool } type argSpec struct { types []jpType variadic bool } type byExprString struct { intr *treeInterpreter node ASTNode items []interface{} hasError bool } func (a *byExprString) Len() int { return len(a.items) } func (a *byExprString) Swap(i, j int) { a.items[i], a.items[j] = a.items[j], a.items[i] } func (a *byExprString) Less(i, j int) bool { first, err := a.intr.Execute(a.node, a.items[i]) if err != nil { a.hasError = true // Return a dummy value. return true } ith, ok := first.(string) if !ok { a.hasError = true return true } second, err := a.intr.Execute(a.node, a.items[j]) if err != nil { a.hasError = true // Return a dummy value. return true } jth, ok := second.(string) if !ok { a.hasError = true return true } return ith < jth } type byExprFloat struct { intr *treeInterpreter node ASTNode items []interface{} hasError bool } func (a *byExprFloat) Len() int { return len(a.items) } func (a *byExprFloat) Swap(i, j int) { a.items[i], a.items[j] = a.items[j], a.items[i] } func (a *byExprFloat) Less(i, j int) bool { first, err := a.intr.Execute(a.node, a.items[i]) if err != nil { a.hasError = true // Return a dummy value. return true } ith, ok := first.(float64) if !ok { a.hasError = true return true } second, err := a.intr.Execute(a.node, a.items[j]) if err != nil { a.hasError = true // Return a dummy value. return true } jth, ok := second.(float64) if !ok { a.hasError = true return true } return ith < jth } type functionCaller struct { functionTable map[string]functionEntry } func newFunctionCaller() *functionCaller { caller := &functionCaller{} caller.functionTable = map[string]functionEntry{ "length": { name: "length", arguments: []argSpec{ {types: []jpType{jpString, jpArray, jpObject}}, }, handler: jpfLength, }, "starts_with": { name: "starts_with", arguments: []argSpec{ {types: []jpType{jpString}}, {types: []jpType{jpString}}, }, handler: jpfStartsWith, }, "abs": { name: "abs", arguments: []argSpec{ {types: []jpType{jpNumber}}, }, handler: jpfAbs, }, "avg": { name: "avg", arguments: []argSpec{ {types: []jpType{jpArrayNumber}}, }, handler: jpfAvg, }, "ceil": { name: "ceil", arguments: []argSpec{ {types: []jpType{jpNumber}}, }, handler: jpfCeil, }, "contains": { name: "contains", arguments: []argSpec{ {types: []jpType{jpArray, jpString}}, {types: []jpType{jpAny}}, }, handler: jpfContains, }, "ends_with": { name: "ends_with", arguments: []argSpec{ {types: []jpType{jpString}}, {types: []jpType{jpString}}, }, handler: jpfEndsWith, }, "floor": { name: "floor", arguments: []argSpec{ {types: []jpType{jpNumber}}, }, handler: jpfFloor, }, "map": { name: "amp", arguments: []argSpec{ {types: []jpType{jpExpref}}, {types: []jpType{jpArray}}, }, handler: jpfMap, hasExpRef: true, }, "max": { name: "max", arguments: []argSpec{ {types: []jpType{jpArrayNumber, jpArrayString}}, }, handler: jpfMax, }, "merge": { name: "merge", arguments: []argSpec{ {types: []jpType{jpObject}, variadic: true}, }, handler: jpfMerge, }, "max_by": { name: "max_by", arguments: []argSpec{ {types: []jpType{jpArray}}, {types: []jpType{jpExpref}}, }, handler: jpfMaxBy, hasExpRef: true, }, "sum": { name: "sum", arguments: []argSpec{ {types: []jpType{jpArrayNumber}}, }, handler: jpfSum, }, "min": { name: "min", arguments: []argSpec{ {types: []jpType{jpArrayNumber, jpArrayString}}, }, handler: jpfMin, }, "min_by": { name: "min_by", arguments: []argSpec{ {types: []jpType{jpArray}}, {types: []jpType{jpExpref}}, }, handler: jpfMinBy, hasExpRef: true, }, "type": { name: "type", arguments: []argSpec{ {types: []jpType{jpAny}}, }, handler: jpfType, }, "keys": { name: "keys", arguments: []argSpec{ {types: []jpType{jpObject}}, }, handler: jpfKeys, }, "values": { name: "values", arguments: []argSpec{ {types: []jpType{jpObject}}, }, handler: jpfValues, }, "sort": { name: "sort", arguments: []argSpec{ {types: []jpType{jpArrayString, jpArrayNumber}}, }, handler: jpfSort, }, "sort_by": { name: "sort_by", arguments: []argSpec{ {types: []jpType{jpArray}}, {types: []jpType{jpExpref}}, }, handler: jpfSortBy, hasExpRef: true, }, "join": { name: "join", arguments: []argSpec{ {types: []jpType{jpString}}, {types: []jpType{jpArrayString}}, }, handler: jpfJoin, }, "reverse": { name: "reverse", arguments: []argSpec{ {types: []jpType{jpArray, jpString}}, }, handler: jpfReverse, }, "to_array": { name: "to_array", arguments: []argSpec{ {types: []jpType{jpAny}}, }, handler: jpfToArray, }, "to_string": { name: "to_string", arguments: []argSpec{ {types: []jpType{jpAny}}, }, handler: jpfToString, }, "to_number": { name: "to_number", arguments: []argSpec{ {types: []jpType{jpAny}}, }, handler: jpfToNumber, }, "not_null": { name: "not_null", arguments: []argSpec{ {types: []jpType{jpAny}, variadic: true}, }, handler: jpfNotNull, }, } return caller } func (e *functionEntry) resolveArgs(arguments []interface{}) ([]interface{}, error) { if len(e.arguments) == 0 { return arguments, nil } if !e.arguments[len(e.arguments)-1].variadic { if len(e.arguments) != len(arguments) { return nil, errors.New("incorrect number of args") } for i, spec := range e.arguments { userArg := arguments[i] err := spec.typeCheck(userArg) if err != nil { return nil, err } } return arguments, nil } if len(arguments) < len(e.arguments) { return nil, errors.New("Invalid arity.") } return arguments, nil } func (a *argSpec) typeCheck(arg interface{}) error { for _, t := range a.types { switch t { case jpNumber: if _, ok := arg.(float64); ok { return nil } case jpString: if _, ok := arg.(string); ok { return nil } case jpArray: if isSliceType(arg) { return nil } case jpObject: if _, ok := arg.(map[string]interface{}); ok { return nil } case jpArrayNumber: if _, ok := toArrayNum(arg); ok { return nil } case jpArrayString: if _, ok := toArrayStr(arg); ok { return nil } case jpAny: return nil case jpExpref: if _, ok := arg.(expRef); ok { return nil } } } return fmt.Errorf("Invalid type for: %v, expected: %#v", arg, a.types) } func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr *treeInterpreter) (interface{}, error) { entry, ok := f.functionTable[name] if !ok { return nil, errors.New("unknown function: " + name) } resolvedArgs, err := entry.resolveArgs(arguments) if err != nil { return nil, err } if entry.hasExpRef { var extra []interface{} extra = append(extra, intr) resolvedArgs = append(extra, resolvedArgs...) } return entry.handler(resolvedArgs) } func jpfAbs(arguments []interface{}) (interface{}, error) { num := arguments[0].(float64) return math.Abs(num), nil } func jpfLength(arguments []interface{}) (interface{}, error) { arg := arguments[0] if c, ok := arg.(string); ok { return float64(utf8.RuneCountInString(c)), nil } else if isSliceType(arg) { v := reflect.ValueOf(arg) return float64(v.Len()), nil } else if c, ok := arg.(map[string]interface{}); ok { return float64(len(c)), nil } return nil, errors.New("could not compute length()") } func jpfStartsWith(arguments []interface{}) (interface{}, error) { search := arguments[0].(string) prefix := arguments[1].(string) return strings.HasPrefix(search, prefix), nil } func jpfAvg(arguments []interface{}) (interface{}, error) { // We've already type checked the value so we can safely use // type assertions. args := arguments[0].([]interface{}) length := float64(len(args)) numerator := 0.0 for _, n := range args { numerator += n.(float64) } return numerator / length, nil } func jpfCeil(arguments []interface{}) (interface{}, error) { val := arguments[0].(float64) return math.Ceil(val), nil } func jpfContains(arguments []interface{}) (interface{}, error) { search := arguments[0] el := arguments[1] if searchStr, ok := search.(string); ok { if elStr, ok := el.(string); ok { return strings.Index(searchStr, elStr) != -1, nil } return false, nil } // Otherwise this is a generic contains for []interface{} general := search.([]interface{}) for _, item := range general { if item == el { return true, nil } } return false, nil } func jpfEndsWith(arguments []interface{}) (interface{}, error) { search := arguments[0].(string) suffix := arguments[1].(string) return strings.HasSuffix(search, suffix), nil } func jpfFloor(arguments []interface{}) (interface{}, error) { val := arguments[0].(float64) return math.Floor(val), nil } func jpfMap(arguments []interface{}) (interface{}, error) { intr := arguments[0].(*treeInterpreter) exp := arguments[1].(expRef) node := exp.ref arr := arguments[2].([]interface{}) mapped := make([]interface{}, 0, len(arr)) for _, value := range arr { current, err := intr.Execute(node, value) if err != nil { return nil, err } mapped = append(mapped, current) } return mapped, nil } func jpfMax(arguments []interface{}) (interface{}, error) { if items, ok := toArrayNum(arguments[0]); ok { if len(items) == 0 { return nil, nil } if len(items) == 1 { return items[0], nil } best := items[0] for _, item := range items[1:] { if item > best { best = item } } return best, nil } // Otherwise we're dealing with a max() of strings. items, _ := toArrayStr(arguments[0]) if len(items) == 0 { return nil, nil } if len(items) == 1 { return items[0], nil } best := items[0] for _, item := range items[1:] { if item > best { best = item } } return best, nil } func jpfMerge(arguments []interface{}) (interface{}, error) { final := make(map[string]interface{}) for _, m := range arguments { mapped := m.(map[string]interface{}) for key, value := range mapped { final[key] = value } } return final, nil } func jpfMaxBy(arguments []interface{}) (interface{}, error) { intr := arguments[0].(*treeInterpreter) arr := arguments[1].([]interface{}) exp := arguments[2].(expRef) node := exp.ref if len(arr) == 0 { return nil, nil } else if len(arr) == 1 { return arr[0], nil } start, err := intr.Execute(node, arr[0]) if err != nil { return nil, err } switch t := start.(type) { case float64: bestVal := t bestItem := arr[0] for _, item := range arr[1:] { result, err := intr.Execute(node, item) if err != nil { return nil, err } current, ok := result.(float64) if !ok { return nil, errors.New("invalid type, must be number") } if current > bestVal { bestVal = current bestItem = item } } return bestItem, nil case string: bestVal := t bestItem := arr[0] for _, item := range arr[1:] { result, err := intr.Execute(node, item) if err != nil { return nil, err } current, ok := result.(string) if !ok { return nil, errors.New("invalid type, must be string") } if current > bestVal { bestVal = current bestItem = item } } return bestItem, nil default: return nil, errors.New("invalid type, must be number of string") } } func jpfSum(arguments []interface{}) (interface{}, error) { items, _ := toArrayNum(arguments[0]) sum := 0.0 for _, item := range items { sum += item } return sum, nil } func jpfMin(arguments []interface{}) (interface{}, error) { if items, ok := toArrayNum(arguments[0]); ok { if len(items) == 0 { return nil, nil } if len(items) == 1 { return items[0], nil } best := items[0] for _, item := range items[1:] { if item < best { best = item } } return best, nil } items, _ := toArrayStr(arguments[0]) if len(items) == 0 { return nil, nil } if len(items) == 1 { return items[0], nil } best := items[0] for _, item := range items[1:] { if item < best { best = item } } return best, nil } func jpfMinBy(arguments []interface{}) (interface{}, error) { intr := arguments[0].(*treeInterpreter) arr := arguments[1].([]interface{}) exp := arguments[2].(expRef) node := exp.ref if len(arr) == 0 { return nil, nil } else if len(arr) == 1 { return arr[0], nil } start, err := intr.Execute(node, arr[0]) if err != nil { return nil, err } if t, ok := start.(float64); ok { bestVal := t bestItem := arr[0] for _, item := range arr[1:] { result, err := intr.Execute(node, item) if err != nil { return nil, err } current, ok := result.(float64) if !ok { return nil, errors.New("invalid type, must be number") } if current < bestVal { bestVal = current bestItem = item } } return bestItem, nil } else if t, ok := start.(string); ok { bestVal := t bestItem := arr[0] for _, item := range arr[1:] { result, err := intr.Execute(node, item) if err != nil { return nil, err } current, ok := result.(string) if !ok { return nil, errors.New("invalid type, must be string") } if current < bestVal { bestVal = current bestItem = item } } return bestItem, nil } else { return nil, errors.New("invalid type, must be number of string") } } func jpfType(arguments []interface{}) (interface{}, error) { arg := arguments[0] if _, ok := arg.(float64); ok { return "number", nil } if _, ok := arg.(string); ok { return "string", nil } if _, ok := arg.([]interface{}); ok { return "array", nil } if _, ok := arg.(map[string]interface{}); ok { return "object", nil } if arg == nil { return "null", nil } if arg == true || arg == false { return "boolean", nil } return nil, errors.New("unknown type") } func jpfKeys(arguments []interface{}) (interface{}, error) { arg := arguments[0].(map[string]interface{}) collected := make([]interface{}, 0, len(arg)) for key := range arg { collected = append(collected, key) } return collected, nil } func jpfValues(arguments []interface{}) (interface{}, error) { arg := arguments[0].(map[string]interface{}) collected := make([]interface{}, 0, len(arg)) for _, value := range arg { collected = append(collected, value) } return collected, nil } func jpfSort(arguments []interface{}) (interface{}, error) { if items, ok := toArrayNum(arguments[0]); ok { d := sort.Float64Slice(items) sort.Stable(d) final := make([]interface{}, len(d)) for i, val := range d { final[i] = val } return final, nil } // Otherwise we're dealing with sort()'ing strings. items, _ := toArrayStr(arguments[0]) d := sort.StringSlice(items) sort.Stable(d) final := make([]interface{}, len(d)) for i, val := range d { final[i] = val } return final, nil } func jpfSortBy(arguments []interface{}) (interface{}, error) { intr := arguments[0].(*treeInterpreter) arr := arguments[1].([]interface{}) exp := arguments[2].(expRef) node := exp.ref if len(arr) == 0 { return arr, nil } else if len(arr) == 1 { return arr, nil } start, err := intr.Execute(node, arr[0]) if err != nil { return nil, err } if _, ok := start.(float64); ok { sortable := &byExprFloat{intr, node, arr, false} sort.Stable(sortable) if sortable.hasError { return nil, errors.New("error in sort_by comparison") } return arr, nil } else if _, ok := start.(string); ok { sortable := &byExprString{intr, node, arr, false} sort.Stable(sortable) if sortable.hasError { return nil, errors.New("error in sort_by comparison") } return arr, nil } else { return nil, errors.New("invalid type, must be number of string") } } func jpfJoin(arguments []interface{}) (interface{}, error) { sep := arguments[0].(string) // We can't just do arguments[1].([]string), we have to // manually convert each item to a string. arrayStr := []string{} for _, item := range arguments[1].([]interface{}) { arrayStr = append(arrayStr, item.(string)) } return strings.Join(arrayStr, sep), nil } func jpfReverse(arguments []interface{}) (interface{}, error) { if s, ok := arguments[0].(string); ok { r := []rune(s) for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return string(r), nil } items := arguments[0].([]interface{}) length := len(items) reversed := make([]interface{}, length) for i, item := range items { reversed[length-(i+1)] = item } return reversed, nil } func jpfToArray(arguments []interface{}) (interface{}, error) { if _, ok := arguments[0].([]interface{}); ok { return arguments[0], nil } return arguments[:1:1], nil } func jpfToString(arguments []interface{}) (interface{}, error) { if v, ok := arguments[0].(string); ok { return v, nil } result, err := json.Marshal(arguments[0]) if err != nil { return nil, err } return string(result), nil } func jpfToNumber(arguments []interface{}) (interface{}, error) { arg := arguments[0] if v, ok := arg.(float64); ok { return v, nil } if v, ok := arg.(string); ok { conv, err := strconv.ParseFloat(v, 64) if err != nil { return nil, nil } return conv, nil } if _, ok := arg.([]interface{}); ok { return nil, nil } if _, ok := arg.(map[string]interface{}); ok { return nil, nil } if arg == nil { return nil, nil } if arg == true || arg == false { return nil, nil } return nil, errors.New("unknown type") } func jpfNotNull(arguments []interface{}) (interface{}, error) { for _, arg := range arguments { if arg != nil { return arg, nil } } return nil, nil } ================================================ FILE: vendor/github.com/jmespath/go-jmespath/interpreter.go ================================================ package jmespath import ( "errors" "reflect" "unicode" "unicode/utf8" ) /* This is a tree based interpreter. It walks the AST and directly interprets the AST to search through a JSON document. */ type treeInterpreter struct { fCall *functionCaller } func newInterpreter() *treeInterpreter { interpreter := treeInterpreter{} interpreter.fCall = newFunctionCaller() return &interpreter } type expRef struct { ref ASTNode } // Execute takes an ASTNode and input data and interprets the AST directly. // It will produce the result of applying the JMESPath expression associated // with the ASTNode to the input data "value". func (intr *treeInterpreter) Execute(node ASTNode, value interface{}) (interface{}, error) { switch node.nodeType { case ASTComparator: left, err := intr.Execute(node.children[0], value) if err != nil { return nil, err } right, err := intr.Execute(node.children[1], value) if err != nil { return nil, err } switch node.value { case tEQ: return objsEqual(left, right), nil case tNE: return !objsEqual(left, right), nil } leftNum, ok := left.(float64) if !ok { return nil, nil } rightNum, ok := right.(float64) if !ok { return nil, nil } switch node.value { case tGT: return leftNum > rightNum, nil case tGTE: return leftNum >= rightNum, nil case tLT: return leftNum < rightNum, nil case tLTE: return leftNum <= rightNum, nil } case ASTExpRef: return expRef{ref: node.children[0]}, nil case ASTFunctionExpression: resolvedArgs := []interface{}{} for _, arg := range node.children { current, err := intr.Execute(arg, value) if err != nil { return nil, err } resolvedArgs = append(resolvedArgs, current) } return intr.fCall.CallFunction(node.value.(string), resolvedArgs, intr) case ASTField: if m, ok := value.(map[string]interface{}); ok { key := node.value.(string) return m[key], nil } return intr.fieldFromStruct(node.value.(string), value) case ASTFilterProjection: left, err := intr.Execute(node.children[0], value) if err != nil { return nil, nil } sliceType, ok := left.([]interface{}) if !ok { if isSliceType(left) { return intr.filterProjectionWithReflection(node, left) } return nil, nil } compareNode := node.children[2] collected := []interface{}{} for _, element := range sliceType { result, err := intr.Execute(compareNode, element) if err != nil { return nil, err } if !isFalse(result) { current, err := intr.Execute(node.children[1], element) if err != nil { return nil, err } if current != nil { collected = append(collected, current) } } } return collected, nil case ASTFlatten: left, err := intr.Execute(node.children[0], value) if err != nil { return nil, nil } sliceType, ok := left.([]interface{}) if !ok { // If we can't type convert to []interface{}, there's // a chance this could still work via reflection if we're // dealing with user provided types. if isSliceType(left) { return intr.flattenWithReflection(left) } return nil, nil } flattened := []interface{}{} for _, element := range sliceType { if elementSlice, ok := element.([]interface{}); ok { flattened = append(flattened, elementSlice...) } else if isSliceType(element) { reflectFlat := []interface{}{} v := reflect.ValueOf(element) for i := 0; i < v.Len(); i++ { reflectFlat = append(reflectFlat, v.Index(i).Interface()) } flattened = append(flattened, reflectFlat...) } else { flattened = append(flattened, element) } } return flattened, nil case ASTIdentity, ASTCurrentNode: return value, nil case ASTIndex: if sliceType, ok := value.([]interface{}); ok { index := node.value.(int) if index < 0 { index += len(sliceType) } if index < len(sliceType) && index >= 0 { return sliceType[index], nil } return nil, nil } // Otherwise try via reflection. rv := reflect.ValueOf(value) if rv.Kind() == reflect.Slice { index := node.value.(int) if index < 0 { index += rv.Len() } if index < rv.Len() && index >= 0 { v := rv.Index(index) return v.Interface(), nil } } return nil, nil case ASTKeyValPair: return intr.Execute(node.children[0], value) case ASTLiteral: return node.value, nil case ASTMultiSelectHash: if value == nil { return nil, nil } collected := make(map[string]interface{}) for _, child := range node.children { current, err := intr.Execute(child, value) if err != nil { return nil, err } key := child.value.(string) collected[key] = current } return collected, nil case ASTMultiSelectList: if value == nil { return nil, nil } collected := []interface{}{} for _, child := range node.children { current, err := intr.Execute(child, value) if err != nil { return nil, err } collected = append(collected, current) } return collected, nil case ASTOrExpression: matched, err := intr.Execute(node.children[0], value) if err != nil { return nil, err } if isFalse(matched) { matched, err = intr.Execute(node.children[1], value) if err != nil { return nil, err } } return matched, nil case ASTAndExpression: matched, err := intr.Execute(node.children[0], value) if err != nil { return nil, err } if isFalse(matched) { return matched, nil } return intr.Execute(node.children[1], value) case ASTNotExpression: matched, err := intr.Execute(node.children[0], value) if err != nil { return nil, err } if isFalse(matched) { return true, nil } return false, nil case ASTPipe: result := value var err error for _, child := range node.children { result, err = intr.Execute(child, result) if err != nil { return nil, err } } return result, nil case ASTProjection: left, err := intr.Execute(node.children[0], value) if err != nil { return nil, err } sliceType, ok := left.([]interface{}) if !ok { if isSliceType(left) { return intr.projectWithReflection(node, left) } return nil, nil } collected := []interface{}{} var current interface{} for _, element := range sliceType { current, err = intr.Execute(node.children[1], element) if err != nil { return nil, err } if current != nil { collected = append(collected, current) } } return collected, nil case ASTSubexpression, ASTIndexExpression: left, err := intr.Execute(node.children[0], value) if err != nil { return nil, err } return intr.Execute(node.children[1], left) case ASTSlice: sliceType, ok := value.([]interface{}) if !ok { if isSliceType(value) { return intr.sliceWithReflection(node, value) } return nil, nil } parts := node.value.([]*int) sliceParams := make([]sliceParam, 3) for i, part := range parts { if part != nil { sliceParams[i].Specified = true sliceParams[i].N = *part } } return slice(sliceType, sliceParams) case ASTValueProjection: left, err := intr.Execute(node.children[0], value) if err != nil { return nil, nil } mapType, ok := left.(map[string]interface{}) if !ok { return nil, nil } values := make([]interface{}, len(mapType)) for _, value := range mapType { values = append(values, value) } collected := []interface{}{} for _, element := range values { current, err := intr.Execute(node.children[1], element) if err != nil { return nil, err } if current != nil { collected = append(collected, current) } } return collected, nil } return nil, errors.New("Unknown AST node: " + node.nodeType.String()) } func (intr *treeInterpreter) fieldFromStruct(key string, value interface{}) (interface{}, error) { rv := reflect.ValueOf(value) first, n := utf8.DecodeRuneInString(key) fieldName := string(unicode.ToUpper(first)) + key[n:] if rv.Kind() == reflect.Struct { v := rv.FieldByName(fieldName) if !v.IsValid() { return nil, nil } return v.Interface(), nil } else if rv.Kind() == reflect.Ptr { // Handle multiple levels of indirection? if rv.IsNil() { return nil, nil } rv = rv.Elem() v := rv.FieldByName(fieldName) if !v.IsValid() { return nil, nil } return v.Interface(), nil } return nil, nil } func (intr *treeInterpreter) flattenWithReflection(value interface{}) (interface{}, error) { v := reflect.ValueOf(value) flattened := []interface{}{} for i := 0; i < v.Len(); i++ { element := v.Index(i).Interface() if reflect.TypeOf(element).Kind() == reflect.Slice { // Then insert the contents of the element // slice into the flattened slice, // i.e flattened = append(flattened, mySlice...) elementV := reflect.ValueOf(element) for j := 0; j < elementV.Len(); j++ { flattened = append( flattened, elementV.Index(j).Interface()) } } else { flattened = append(flattened, element) } } return flattened, nil } func (intr *treeInterpreter) sliceWithReflection(node ASTNode, value interface{}) (interface{}, error) { v := reflect.ValueOf(value) parts := node.value.([]*int) sliceParams := make([]sliceParam, 3) for i, part := range parts { if part != nil { sliceParams[i].Specified = true sliceParams[i].N = *part } } final := []interface{}{} for i := 0; i < v.Len(); i++ { element := v.Index(i).Interface() final = append(final, element) } return slice(final, sliceParams) } func (intr *treeInterpreter) filterProjectionWithReflection(node ASTNode, value interface{}) (interface{}, error) { compareNode := node.children[2] collected := []interface{}{} v := reflect.ValueOf(value) for i := 0; i < v.Len(); i++ { element := v.Index(i).Interface() result, err := intr.Execute(compareNode, element) if err != nil { return nil, err } if !isFalse(result) { current, err := intr.Execute(node.children[1], element) if err != nil { return nil, err } if current != nil { collected = append(collected, current) } } } return collected, nil } func (intr *treeInterpreter) projectWithReflection(node ASTNode, value interface{}) (interface{}, error) { collected := []interface{}{} v := reflect.ValueOf(value) for i := 0; i < v.Len(); i++ { element := v.Index(i).Interface() result, err := intr.Execute(node.children[1], element) if err != nil { return nil, err } if result != nil { collected = append(collected, result) } } return collected, nil } ================================================ FILE: vendor/github.com/jmespath/go-jmespath/lexer.go ================================================ package jmespath import ( "bytes" "encoding/json" "fmt" "strconv" "strings" "unicode/utf8" ) type token struct { tokenType tokType value string position int length int } type tokType int const eof = -1 // Lexer contains information about the expression being tokenized. type Lexer struct { expression string // The expression provided by the user. currentPos int // The current position in the string. lastWidth int // The width of the current rune. This buf bytes.Buffer // Internal buffer used for building up values. } // SyntaxError is the main error used whenever a lexing or parsing error occurs. type SyntaxError struct { msg string // Error message displayed to user Expression string // Expression that generated a SyntaxError Offset int // The location in the string where the error occurred } func (e SyntaxError) Error() string { // In the future, it would be good to underline the specific // location where the error occurred. return "SyntaxError: " + e.msg } // HighlightLocation will show where the syntax error occurred. // It will place a "^" character on a line below the expression // at the point where the syntax error occurred. func (e SyntaxError) HighlightLocation() string { return e.Expression + "\n" + strings.Repeat(" ", e.Offset) + "^" } //go:generate stringer -type=tokType const ( tUnknown tokType = iota tStar tDot tFilter tFlatten tLparen tRparen tLbracket tRbracket tLbrace tRbrace tOr tPipe tNumber tUnquotedIdentifier tQuotedIdentifier tComma tColon tLT tLTE tGT tGTE tEQ tNE tJSONLiteral tStringLiteral tCurrent tExpref tAnd tNot tEOF ) var basicTokens = map[rune]tokType{ '.': tDot, '*': tStar, ',': tComma, ':': tColon, '{': tLbrace, '}': tRbrace, ']': tRbracket, // tLbracket not included because it could be "[]" '(': tLparen, ')': tRparen, '@': tCurrent, } // Bit mask for [a-zA-Z_] shifted down 64 bits to fit in a single uint64. // When using this bitmask just be sure to shift the rune down 64 bits // before checking against identifierStartBits. const identifierStartBits uint64 = 576460745995190270 // Bit mask for [a-zA-Z0-9], 128 bits -> 2 uint64s. var identifierTrailingBits = [2]uint64{287948901175001088, 576460745995190270} var whiteSpace = map[rune]bool{ ' ': true, '\t': true, '\n': true, '\r': true, } func (t token) String() string { return fmt.Sprintf("Token{%+v, %s, %d, %d}", t.tokenType, t.value, t.position, t.length) } // NewLexer creates a new JMESPath lexer. func NewLexer() *Lexer { lexer := Lexer{} return &lexer } func (lexer *Lexer) next() rune { if lexer.currentPos >= len(lexer.expression) { lexer.lastWidth = 0 return eof } r, w := utf8.DecodeRuneInString(lexer.expression[lexer.currentPos:]) lexer.lastWidth = w lexer.currentPos += w return r } func (lexer *Lexer) back() { lexer.currentPos -= lexer.lastWidth } func (lexer *Lexer) peek() rune { t := lexer.next() lexer.back() return t } // tokenize takes an expression and returns corresponding tokens. func (lexer *Lexer) tokenize(expression string) ([]token, error) { var tokens []token lexer.expression = expression lexer.currentPos = 0 lexer.lastWidth = 0 loop: for { r := lexer.next() if identifierStartBits&(1<<(uint64(r)-64)) > 0 { t := lexer.consumeUnquotedIdentifier() tokens = append(tokens, t) } else if val, ok := basicTokens[r]; ok { // Basic single char token. t := token{ tokenType: val, value: string(r), position: lexer.currentPos - lexer.lastWidth, length: 1, } tokens = append(tokens, t) } else if r == '-' || (r >= '0' && r <= '9') { t := lexer.consumeNumber() tokens = append(tokens, t) } else if r == '[' { t := lexer.consumeLBracket() tokens = append(tokens, t) } else if r == '"' { t, err := lexer.consumeQuotedIdentifier() if err != nil { return tokens, err } tokens = append(tokens, t) } else if r == '\'' { t, err := lexer.consumeRawStringLiteral() if err != nil { return tokens, err } tokens = append(tokens, t) } else if r == '`' { t, err := lexer.consumeLiteral() if err != nil { return tokens, err } tokens = append(tokens, t) } else if r == '|' { t := lexer.matchOrElse(r, '|', tOr, tPipe) tokens = append(tokens, t) } else if r == '<' { t := lexer.matchOrElse(r, '=', tLTE, tLT) tokens = append(tokens, t) } else if r == '>' { t := lexer.matchOrElse(r, '=', tGTE, tGT) tokens = append(tokens, t) } else if r == '!' { t := lexer.matchOrElse(r, '=', tNE, tNot) tokens = append(tokens, t) } else if r == '=' { t := lexer.matchOrElse(r, '=', tEQ, tUnknown) tokens = append(tokens, t) } else if r == '&' { t := lexer.matchOrElse(r, '&', tAnd, tExpref) tokens = append(tokens, t) } else if r == eof { break loop } else if _, ok := whiteSpace[r]; ok { // Ignore whitespace } else { return tokens, lexer.syntaxError(fmt.Sprintf("Unknown char: %s", strconv.QuoteRuneToASCII(r))) } } tokens = append(tokens, token{tEOF, "", len(lexer.expression), 0}) return tokens, nil } // Consume characters until the ending rune "r" is reached. // If the end of the expression is reached before seeing the // terminating rune "r", then an error is returned. // If no error occurs then the matching substring is returned. // The returned string will not include the ending rune. func (lexer *Lexer) consumeUntil(end rune) (string, error) { start := lexer.currentPos current := lexer.next() for current != end && current != eof { if current == '\\' && lexer.peek() != eof { lexer.next() } current = lexer.next() } if lexer.lastWidth == 0 { // Then we hit an EOF so we never reached the closing // delimiter. return "", SyntaxError{ msg: "Unclosed delimiter: " + string(end), Expression: lexer.expression, Offset: len(lexer.expression), } } return lexer.expression[start : lexer.currentPos-lexer.lastWidth], nil } func (lexer *Lexer) consumeLiteral() (token, error) { start := lexer.currentPos value, err := lexer.consumeUntil('`') if err != nil { return token{}, err } value = strings.Replace(value, "\\`", "`", -1) return token{ tokenType: tJSONLiteral, value: value, position: start, length: len(value), }, nil } func (lexer *Lexer) consumeRawStringLiteral() (token, error) { start := lexer.currentPos currentIndex := start current := lexer.next() for current != '\'' && lexer.peek() != eof { if current == '\\' && lexer.peek() == '\'' { chunk := lexer.expression[currentIndex : lexer.currentPos-1] lexer.buf.WriteString(chunk) lexer.buf.WriteString("'") lexer.next() currentIndex = lexer.currentPos } current = lexer.next() } if lexer.lastWidth == 0 { // Then we hit an EOF so we never reached the closing // delimiter. return token{}, SyntaxError{ msg: "Unclosed delimiter: '", Expression: lexer.expression, Offset: len(lexer.expression), } } if currentIndex < lexer.currentPos { lexer.buf.WriteString(lexer.expression[currentIndex : lexer.currentPos-1]) } value := lexer.buf.String() // Reset the buffer so it can reused again. lexer.buf.Reset() return token{ tokenType: tStringLiteral, value: value, position: start, length: len(value), }, nil } func (lexer *Lexer) syntaxError(msg string) SyntaxError { return SyntaxError{ msg: msg, Expression: lexer.expression, Offset: lexer.currentPos - 1, } } // Checks for a two char token, otherwise matches a single character // token. This is used whenever a two char token overlaps a single // char token, e.g. "||" -> tPipe, "|" -> tOr. func (lexer *Lexer) matchOrElse(first rune, second rune, matchedType tokType, singleCharType tokType) token { start := lexer.currentPos - lexer.lastWidth nextRune := lexer.next() var t token if nextRune == second { t = token{ tokenType: matchedType, value: string(first) + string(second), position: start, length: 2, } } else { lexer.back() t = token{ tokenType: singleCharType, value: string(first), position: start, length: 1, } } return t } func (lexer *Lexer) consumeLBracket() token { // There's three options here: // 1. A filter expression "[?" // 2. A flatten operator "[]" // 3. A bare rbracket "[" start := lexer.currentPos - lexer.lastWidth nextRune := lexer.next() var t token if nextRune == '?' { t = token{ tokenType: tFilter, value: "[?", position: start, length: 2, } } else if nextRune == ']' { t = token{ tokenType: tFlatten, value: "[]", position: start, length: 2, } } else { t = token{ tokenType: tLbracket, value: "[", position: start, length: 1, } lexer.back() } return t } func (lexer *Lexer) consumeQuotedIdentifier() (token, error) { start := lexer.currentPos value, err := lexer.consumeUntil('"') if err != nil { return token{}, err } var decoded string asJSON := []byte("\"" + value + "\"") if err := json.Unmarshal([]byte(asJSON), &decoded); err != nil { return token{}, err } return token{ tokenType: tQuotedIdentifier, value: decoded, position: start - 1, length: len(decoded), }, nil } func (lexer *Lexer) consumeUnquotedIdentifier() token { // Consume runes until we reach the end of an unquoted // identifier. start := lexer.currentPos - lexer.lastWidth for { r := lexer.next() if r < 0 || r > 128 || identifierTrailingBits[uint64(r)/64]&(1<<(uint64(r)%64)) == 0 { lexer.back() break } } value := lexer.expression[start:lexer.currentPos] return token{ tokenType: tUnquotedIdentifier, value: value, position: start, length: lexer.currentPos - start, } } func (lexer *Lexer) consumeNumber() token { // Consume runes until we reach something that's not a number. start := lexer.currentPos - lexer.lastWidth for { r := lexer.next() if r < '0' || r > '9' { lexer.back() break } } value := lexer.expression[start:lexer.currentPos] return token{ tokenType: tNumber, value: value, position: start, length: lexer.currentPos - start, } } ================================================ FILE: vendor/github.com/jmespath/go-jmespath/parser.go ================================================ package jmespath import ( "encoding/json" "fmt" "strconv" "strings" ) type astNodeType int //go:generate stringer -type astNodeType const ( ASTEmpty astNodeType = iota ASTComparator ASTCurrentNode ASTExpRef ASTFunctionExpression ASTField ASTFilterProjection ASTFlatten ASTIdentity ASTIndex ASTIndexExpression ASTKeyValPair ASTLiteral ASTMultiSelectHash ASTMultiSelectList ASTOrExpression ASTAndExpression ASTNotExpression ASTPipe ASTProjection ASTSubexpression ASTSlice ASTValueProjection ) // ASTNode represents the abstract syntax tree of a JMESPath expression. type ASTNode struct { nodeType astNodeType value interface{} children []ASTNode } func (node ASTNode) String() string { return node.PrettyPrint(0) } // PrettyPrint will pretty print the parsed AST. // The AST is an implementation detail and this pretty print // function is provided as a convenience method to help with // debugging. You should not rely on its output as the internal // structure of the AST may change at any time. func (node ASTNode) PrettyPrint(indent int) string { spaces := strings.Repeat(" ", indent) output := fmt.Sprintf("%s%s {\n", spaces, node.nodeType) nextIndent := indent + 2 if node.value != nil { if converted, ok := node.value.(fmt.Stringer); ok { // Account for things like comparator nodes // that are enums with a String() method. output += fmt.Sprintf("%svalue: %s\n", strings.Repeat(" ", nextIndent), converted.String()) } else { output += fmt.Sprintf("%svalue: %#v\n", strings.Repeat(" ", nextIndent), node.value) } } lastIndex := len(node.children) if lastIndex > 0 { output += fmt.Sprintf("%schildren: {\n", strings.Repeat(" ", nextIndent)) childIndent := nextIndent + 2 for _, elem := range node.children { output += elem.PrettyPrint(childIndent) } } output += fmt.Sprintf("%s}\n", spaces) return output } var bindingPowers = map[tokType]int{ tEOF: 0, tUnquotedIdentifier: 0, tQuotedIdentifier: 0, tRbracket: 0, tRparen: 0, tComma: 0, tRbrace: 0, tNumber: 0, tCurrent: 0, tExpref: 0, tColon: 0, tPipe: 1, tOr: 2, tAnd: 3, tEQ: 5, tLT: 5, tLTE: 5, tGT: 5, tGTE: 5, tNE: 5, tFlatten: 9, tStar: 20, tFilter: 21, tDot: 40, tNot: 45, tLbrace: 50, tLbracket: 55, tLparen: 60, } // Parser holds state about the current expression being parsed. type Parser struct { expression string tokens []token index int } // NewParser creates a new JMESPath parser. func NewParser() *Parser { p := Parser{} return &p } // Parse will compile a JMESPath expression. func (p *Parser) Parse(expression string) (ASTNode, error) { lexer := NewLexer() p.expression = expression p.index = 0 tokens, err := lexer.tokenize(expression) if err != nil { return ASTNode{}, err } p.tokens = tokens parsed, err := p.parseExpression(0) if err != nil { return ASTNode{}, err } if p.current() != tEOF { return ASTNode{}, p.syntaxError(fmt.Sprintf( "Unexpected token at the end of the expresssion: %s", p.current())) } return parsed, nil } func (p *Parser) parseExpression(bindingPower int) (ASTNode, error) { var err error leftToken := p.lookaheadToken(0) p.advance() leftNode, err := p.nud(leftToken) if err != nil { return ASTNode{}, err } currentToken := p.current() for bindingPower < bindingPowers[currentToken] { p.advance() leftNode, err = p.led(currentToken, leftNode) if err != nil { return ASTNode{}, err } currentToken = p.current() } return leftNode, nil } func (p *Parser) parseIndexExpression() (ASTNode, error) { if p.lookahead(0) == tColon || p.lookahead(1) == tColon { return p.parseSliceExpression() } indexStr := p.lookaheadToken(0).value parsedInt, err := strconv.Atoi(indexStr) if err != nil { return ASTNode{}, err } indexNode := ASTNode{nodeType: ASTIndex, value: parsedInt} p.advance() if err := p.match(tRbracket); err != nil { return ASTNode{}, err } return indexNode, nil } func (p *Parser) parseSliceExpression() (ASTNode, error) { parts := []*int{nil, nil, nil} index := 0 current := p.current() for current != tRbracket && index < 3 { if current == tColon { index++ p.advance() } else if current == tNumber { parsedInt, err := strconv.Atoi(p.lookaheadToken(0).value) if err != nil { return ASTNode{}, err } parts[index] = &parsedInt p.advance() } else { return ASTNode{}, p.syntaxError( "Expected tColon or tNumber" + ", received: " + p.current().String()) } current = p.current() } if err := p.match(tRbracket); err != nil { return ASTNode{}, err } return ASTNode{ nodeType: ASTSlice, value: parts, }, nil } func (p *Parser) match(tokenType tokType) error { if p.current() == tokenType { p.advance() return nil } return p.syntaxError("Expected " + tokenType.String() + ", received: " + p.current().String()) } func (p *Parser) led(tokenType tokType, node ASTNode) (ASTNode, error) { switch tokenType { case tDot: if p.current() != tStar { right, err := p.parseDotRHS(bindingPowers[tDot]) return ASTNode{ nodeType: ASTSubexpression, children: []ASTNode{node, right}, }, err } p.advance() right, err := p.parseProjectionRHS(bindingPowers[tDot]) return ASTNode{ nodeType: ASTValueProjection, children: []ASTNode{node, right}, }, err case tPipe: right, err := p.parseExpression(bindingPowers[tPipe]) return ASTNode{nodeType: ASTPipe, children: []ASTNode{node, right}}, err case tOr: right, err := p.parseExpression(bindingPowers[tOr]) return ASTNode{nodeType: ASTOrExpression, children: []ASTNode{node, right}}, err case tAnd: right, err := p.parseExpression(bindingPowers[tAnd]) return ASTNode{nodeType: ASTAndExpression, children: []ASTNode{node, right}}, err case tLparen: name := node.value var args []ASTNode for p.current() != tRparen { expression, err := p.parseExpression(0) if err != nil { return ASTNode{}, err } if p.current() == tComma { if err := p.match(tComma); err != nil { return ASTNode{}, err } } args = append(args, expression) } if err := p.match(tRparen); err != nil { return ASTNode{}, err } return ASTNode{ nodeType: ASTFunctionExpression, value: name, children: args, }, nil case tFilter: return p.parseFilter(node) case tFlatten: left := ASTNode{nodeType: ASTFlatten, children: []ASTNode{node}} right, err := p.parseProjectionRHS(bindingPowers[tFlatten]) return ASTNode{ nodeType: ASTProjection, children: []ASTNode{left, right}, }, err case tEQ, tNE, tGT, tGTE, tLT, tLTE: right, err := p.parseExpression(bindingPowers[tokenType]) if err != nil { return ASTNode{}, err } return ASTNode{ nodeType: ASTComparator, value: tokenType, children: []ASTNode{node, right}, }, nil case tLbracket: tokenType := p.current() var right ASTNode var err error if tokenType == tNumber || tokenType == tColon { right, err = p.parseIndexExpression() if err != nil { return ASTNode{}, err } return p.projectIfSlice(node, right) } // Otherwise this is a projection. if err := p.match(tStar); err != nil { return ASTNode{}, err } if err := p.match(tRbracket); err != nil { return ASTNode{}, err } right, err = p.parseProjectionRHS(bindingPowers[tStar]) if err != nil { return ASTNode{}, err } return ASTNode{ nodeType: ASTProjection, children: []ASTNode{node, right}, }, nil } return ASTNode{}, p.syntaxError("Unexpected token: " + tokenType.String()) } func (p *Parser) nud(token token) (ASTNode, error) { switch token.tokenType { case tJSONLiteral: var parsed interface{} err := json.Unmarshal([]byte(token.value), &parsed) if err != nil { return ASTNode{}, err } return ASTNode{nodeType: ASTLiteral, value: parsed}, nil case tStringLiteral: return ASTNode{nodeType: ASTLiteral, value: token.value}, nil case tUnquotedIdentifier: return ASTNode{ nodeType: ASTField, value: token.value, }, nil case tQuotedIdentifier: node := ASTNode{nodeType: ASTField, value: token.value} if p.current() == tLparen { return ASTNode{}, p.syntaxErrorToken("Can't have quoted identifier as function name.", token) } return node, nil case tStar: left := ASTNode{nodeType: ASTIdentity} var right ASTNode var err error if p.current() == tRbracket { right = ASTNode{nodeType: ASTIdentity} } else { right, err = p.parseProjectionRHS(bindingPowers[tStar]) } return ASTNode{nodeType: ASTValueProjection, children: []ASTNode{left, right}}, err case tFilter: return p.parseFilter(ASTNode{nodeType: ASTIdentity}) case tLbrace: return p.parseMultiSelectHash() case tFlatten: left := ASTNode{ nodeType: ASTFlatten, children: []ASTNode{{nodeType: ASTIdentity}}, } right, err := p.parseProjectionRHS(bindingPowers[tFlatten]) if err != nil { return ASTNode{}, err } return ASTNode{nodeType: ASTProjection, children: []ASTNode{left, right}}, nil case tLbracket: tokenType := p.current() //var right ASTNode if tokenType == tNumber || tokenType == tColon { right, err := p.parseIndexExpression() if err != nil { return ASTNode{}, nil } return p.projectIfSlice(ASTNode{nodeType: ASTIdentity}, right) } else if tokenType == tStar && p.lookahead(1) == tRbracket { p.advance() p.advance() right, err := p.parseProjectionRHS(bindingPowers[tStar]) if err != nil { return ASTNode{}, err } return ASTNode{ nodeType: ASTProjection, children: []ASTNode{{nodeType: ASTIdentity}, right}, }, nil } else { return p.parseMultiSelectList() } case tCurrent: return ASTNode{nodeType: ASTCurrentNode}, nil case tExpref: expression, err := p.parseExpression(bindingPowers[tExpref]) if err != nil { return ASTNode{}, err } return ASTNode{nodeType: ASTExpRef, children: []ASTNode{expression}}, nil case tNot: expression, err := p.parseExpression(bindingPowers[tNot]) if err != nil { return ASTNode{}, err } return ASTNode{nodeType: ASTNotExpression, children: []ASTNode{expression}}, nil case tLparen: expression, err := p.parseExpression(0) if err != nil { return ASTNode{}, err } if err := p.match(tRparen); err != nil { return ASTNode{}, err } return expression, nil case tEOF: return ASTNode{}, p.syntaxErrorToken("Incomplete expression", token) } return ASTNode{}, p.syntaxErrorToken("Invalid token: "+token.tokenType.String(), token) } func (p *Parser) parseMultiSelectList() (ASTNode, error) { var expressions []ASTNode for { expression, err := p.parseExpression(0) if err != nil { return ASTNode{}, err } expressions = append(expressions, expression) if p.current() == tRbracket { break } err = p.match(tComma) if err != nil { return ASTNode{}, err } } err := p.match(tRbracket) if err != nil { return ASTNode{}, err } return ASTNode{ nodeType: ASTMultiSelectList, children: expressions, }, nil } func (p *Parser) parseMultiSelectHash() (ASTNode, error) { var children []ASTNode for { keyToken := p.lookaheadToken(0) if err := p.match(tUnquotedIdentifier); err != nil { if err := p.match(tQuotedIdentifier); err != nil { return ASTNode{}, p.syntaxError("Expected tQuotedIdentifier or tUnquotedIdentifier") } } keyName := keyToken.value err := p.match(tColon) if err != nil { return ASTNode{}, err } value, err := p.parseExpression(0) if err != nil { return ASTNode{}, err } node := ASTNode{ nodeType: ASTKeyValPair, value: keyName, children: []ASTNode{value}, } children = append(children, node) if p.current() == tComma { err := p.match(tComma) if err != nil { return ASTNode{}, nil } } else if p.current() == tRbrace { err := p.match(tRbrace) if err != nil { return ASTNode{}, nil } break } } return ASTNode{ nodeType: ASTMultiSelectHash, children: children, }, nil } func (p *Parser) projectIfSlice(left ASTNode, right ASTNode) (ASTNode, error) { indexExpr := ASTNode{ nodeType: ASTIndexExpression, children: []ASTNode{left, right}, } if right.nodeType == ASTSlice { right, err := p.parseProjectionRHS(bindingPowers[tStar]) return ASTNode{ nodeType: ASTProjection, children: []ASTNode{indexExpr, right}, }, err } return indexExpr, nil } func (p *Parser) parseFilter(node ASTNode) (ASTNode, error) { var right, condition ASTNode var err error condition, err = p.parseExpression(0) if err != nil { return ASTNode{}, err } if err := p.match(tRbracket); err != nil { return ASTNode{}, err } if p.current() == tFlatten { right = ASTNode{nodeType: ASTIdentity} } else { right, err = p.parseProjectionRHS(bindingPowers[tFilter]) if err != nil { return ASTNode{}, err } } return ASTNode{ nodeType: ASTFilterProjection, children: []ASTNode{node, right, condition}, }, nil } func (p *Parser) parseDotRHS(bindingPower int) (ASTNode, error) { lookahead := p.current() if tokensOneOf([]tokType{tQuotedIdentifier, tUnquotedIdentifier, tStar}, lookahead) { return p.parseExpression(bindingPower) } else if lookahead == tLbracket { if err := p.match(tLbracket); err != nil { return ASTNode{}, err } return p.parseMultiSelectList() } else if lookahead == tLbrace { if err := p.match(tLbrace); err != nil { return ASTNode{}, err } return p.parseMultiSelectHash() } return ASTNode{}, p.syntaxError("Expected identifier, lbracket, or lbrace") } func (p *Parser) parseProjectionRHS(bindingPower int) (ASTNode, error) { current := p.current() if bindingPowers[current] < 10 { return ASTNode{nodeType: ASTIdentity}, nil } else if current == tLbracket { return p.parseExpression(bindingPower) } else if current == tFilter { return p.parseExpression(bindingPower) } else if current == tDot { err := p.match(tDot) if err != nil { return ASTNode{}, err } return p.parseDotRHS(bindingPower) } else { return ASTNode{}, p.syntaxError("Error") } } func (p *Parser) lookahead(number int) tokType { return p.lookaheadToken(number).tokenType } func (p *Parser) current() tokType { return p.lookahead(0) } func (p *Parser) lookaheadToken(number int) token { return p.tokens[p.index+number] } func (p *Parser) advance() { p.index++ } func tokensOneOf(elements []tokType, token tokType) bool { for _, elem := range elements { if elem == token { return true } } return false } func (p *Parser) syntaxError(msg string) SyntaxError { return SyntaxError{ msg: msg, Expression: p.expression, Offset: p.lookaheadToken(0).position, } } // Create a SyntaxError based on the provided token. // This differs from syntaxError() which creates a SyntaxError // based on the current lookahead token. func (p *Parser) syntaxErrorToken(msg string, t token) SyntaxError { return SyntaxError{ msg: msg, Expression: p.expression, Offset: t.position, } } ================================================ FILE: vendor/github.com/jmespath/go-jmespath/toktype_string.go ================================================ // generated by stringer -type=tokType; DO NOT EDIT package jmespath import "fmt" const _tokType_name = "tUnknowntStartDottFiltertFlattentLparentRparentLbrackettRbrackettLbracetRbracetOrtPipetNumbertUnquotedIdentifiertQuotedIdentifiertCommatColontLTtLTEtGTtGTEtEQtNEtJSONLiteraltStringLiteraltCurrenttExpreftAndtNottEOF" var _tokType_index = [...]uint8{0, 8, 13, 17, 24, 32, 39, 46, 55, 64, 71, 78, 81, 86, 93, 112, 129, 135, 141, 144, 148, 151, 155, 158, 161, 173, 187, 195, 202, 206, 210, 214} func (i tokType) String() string { if i < 0 || i >= tokType(len(_tokType_index)-1) { return fmt.Sprintf("tokType(%d)", i) } return _tokType_name[_tokType_index[i]:_tokType_index[i+1]] } ================================================ FILE: vendor/github.com/jmespath/go-jmespath/util.go ================================================ package jmespath import ( "errors" "reflect" ) // IsFalse determines if an object is false based on the JMESPath spec. // JMESPath defines false values to be any of: // - An empty string array, or hash. // - The boolean value false. // - nil func isFalse(value interface{}) bool { switch v := value.(type) { case bool: return !v case []interface{}: return len(v) == 0 case map[string]interface{}: return len(v) == 0 case string: return len(v) == 0 case nil: return true } // Try the reflection cases before returning false. rv := reflect.ValueOf(value) switch rv.Kind() { case reflect.Struct: // A struct type will never be false, even if // all of its values are the zero type. return false case reflect.Slice, reflect.Map: return rv.Len() == 0 case reflect.Ptr: if rv.IsNil() { return true } // If it's a pointer type, we'll try to deref the pointer // and evaluate the pointer value for isFalse. element := rv.Elem() return isFalse(element.Interface()) } return false } // ObjsEqual is a generic object equality check. // It will take two arbitrary objects and recursively determine // if they are equal. func objsEqual(left interface{}, right interface{}) bool { return reflect.DeepEqual(left, right) } // SliceParam refers to a single part of a slice. // A slice consists of a start, a stop, and a step, similar to // python slices. type sliceParam struct { N int Specified bool } // Slice supports [start:stop:step] style slicing that's supported in JMESPath. func slice(slice []interface{}, parts []sliceParam) ([]interface{}, error) { computed, err := computeSliceParams(len(slice), parts) if err != nil { return nil, err } start, stop, step := computed[0], computed[1], computed[2] result := []interface{}{} if step > 0 { for i := start; i < stop; i += step { result = append(result, slice[i]) } } else { for i := start; i > stop; i += step { result = append(result, slice[i]) } } return result, nil } func computeSliceParams(length int, parts []sliceParam) ([]int, error) { var start, stop, step int if !parts[2].Specified { step = 1 } else if parts[2].N == 0 { return nil, errors.New("Invalid slice, step cannot be 0") } else { step = parts[2].N } var stepValueNegative bool if step < 0 { stepValueNegative = true } else { stepValueNegative = false } if !parts[0].Specified { if stepValueNegative { start = length - 1 } else { start = 0 } } else { start = capSlice(length, parts[0].N, step) } if !parts[1].Specified { if stepValueNegative { stop = -1 } else { stop = length } } else { stop = capSlice(length, parts[1].N, step) } return []int{start, stop, step}, nil } func capSlice(length int, actual int, step int) int { if actual < 0 { actual += length if actual < 0 { if step < 0 { actual = -1 } else { actual = 0 } } } else if actual >= length { if step < 0 { actual = length - 1 } else { actual = length } } return actual } // ToArrayNum converts an empty interface type to a slice of float64. // If any element in the array cannot be converted, then nil is returned // along with a second value of false. func toArrayNum(data interface{}) ([]float64, bool) { // Is there a better way to do this with reflect? if d, ok := data.([]interface{}); ok { result := make([]float64, len(d)) for i, el := range d { item, ok := el.(float64) if !ok { return nil, false } result[i] = item } return result, true } return nil, false } // ToArrayStr converts an empty interface type to a slice of strings. // If any element in the array cannot be converted, then nil is returned // along with a second value of false. If the input data could be entirely // converted, then the converted data, along with a second value of true, // will be returned. func toArrayStr(data interface{}) ([]string, bool) { // Is there a better way to do this with reflect? if d, ok := data.([]interface{}); ok { result := make([]string, len(d)) for i, el := range d { item, ok := el.(string) if !ok { return nil, false } result[i] = item } return result, true } return nil, false } func isSliceType(v interface{}) bool { if v == nil { return false } return reflect.TypeOf(v).Kind() == reflect.Slice } ================================================ FILE: vendor/vendor.json ================================================ { "comment": "", "ignore": "test", "package": [ { "checksumSHA1": "Ex4zN+CcY/wtoDoK/penrVAxAok=", "path": "github.com/aws/aws-sdk-go/aws", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "Y9W+4GimK4Fuxq+vyIskVYFRnX4=", "path": "github.com/aws/aws-sdk-go/aws/awserr", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "+q4vdl3l1Wom8K1wfIpJ4jlFsbY=", "path": "github.com/aws/aws-sdk-go/aws/awsutil", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "H/tMKHZU+Qka6RtYiGB50s2uA0s=", "path": "github.com/aws/aws-sdk-go/aws/client", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "ieAJ+Cvp/PKv1LpUEnUXpc3OI6E=", "path": "github.com/aws/aws-sdk-go/aws/client/metadata", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "gNWirlrTfSLbOe421hISBAhTqa4=", "path": "github.com/aws/aws-sdk-go/aws/corehandlers", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "dNZNaOPfBPnzE2CBnfhXXZ9g9jU=", "path": "github.com/aws/aws-sdk-go/aws/credentials", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "KQiUK/zr3mqnAXD7x/X55/iNme0=", "path": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "NUJUTWlc1sV8b7WjfiYc4JZbXl0=", "path": "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "4Ipx+5xN0gso+cENC2MHMWmQlR4=", "path": "github.com/aws/aws-sdk-go/aws/credentials/stscreds", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "nCMd1XKjgV21bEl7J8VZFqTV8PE=", "path": "github.com/aws/aws-sdk-go/aws/defaults", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "U0SthWum+t9ACanK7SDJOg3dO6M=", "path": "github.com/aws/aws-sdk-go/aws/ec2metadata", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "NyUg1P8ZS/LHAAQAk/4C5O4X3og=", "path": "github.com/aws/aws-sdk-go/aws/request", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "44uohX3kLsfZHHOqunr+qJnSCdw=", "path": "github.com/aws/aws-sdk-go/aws/session", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "7lla+sckQeF18wORAGuU2fFMlp4=", "path": "github.com/aws/aws-sdk-go/aws/signer/v4", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "Bm6UrYb2QCzpYseLwwgw6aetgRc=", "path": "github.com/aws/aws-sdk-go/private/endpoints", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "wk7EyvDaHwb5qqoOP/4d3cV0708=", "path": "github.com/aws/aws-sdk-go/private/protocol", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "pNeF0Ey7TfBArH5LBQhKOQXQbLY=", "path": "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "H9TymcQkQnXSXSVfjggiiS4bpzM=", "path": "github.com/aws/aws-sdk-go/private/protocol/jsonrpc", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "isoix7lTx4qIq2zI2xFADtti5SI=", "path": "github.com/aws/aws-sdk-go/private/protocol/query", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "5xzix1R8prUyWxgLnzUQoxTsfik=", "path": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "TW/7U+/8ormL7acf6z2rv2hDD+s=", "path": "github.com/aws/aws-sdk-go/private/protocol/rest", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "eUEkjyMPAuekKBE4ou+nM9tXEas=", "path": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "sP/qEaDICVBV3rRw2sl759YI0iw=", "path": "github.com/aws/aws-sdk-go/service/cloudwatchlogs", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "nH/itbdeFHpl4ysegdtgww9bFSA=", "path": "github.com/aws/aws-sdk-go/service/sts", "revision": "d54f7c6d021d8fca3275e29d13255ededdc54839", "revisionTime": "2016-09-15T23:18:18Z" }, { "checksumSHA1": "8C6hbcW3iPuwRfWoOWFtg4ca5sk=", "path": "github.com/coreos/go-systemd/sdjournal", "revision": "2f344660b11f7285b0af86195c4456e92970f640", "revisionTime": "2016-09-07T12:16:35Z" }, { "checksumSHA1": "O8c/VKtW34XPJNNlyeb/im8vWSI=", "path": "github.com/coreos/pkg/dlopen", "revision": "3ac0863d7acf3bc44daf49afef8919af12f704ef", "revisionTime": "2016-07-27T23:37:14Z" }, { "checksumSHA1": "cVyhKIRI2gQrgpn5qrBeAqErmWM=", "origin": "github.com/aws/aws-sdk-go/vendor/github.com/go-ini/ini", "path": "github.com/go-ini/ini", "revision": "6e4869b434bd001f6983749881c7ead3545887d8", "revisionTime": "2016-08-27T06:11:18Z" }, { "path": "github.com/hashicorp/hcl", "revision": "" }, { "checksumSHA1": "67DfevLBglV52Y2eAuhFc/xQni0=", "path": "github.com/hashicorp/hcl/hcl/ast", "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", "revisionTime": "2016-09-02T16:52:19Z" }, { "checksumSHA1": "lgR7PSAZ0RtvAc9OCtCnNsF/x8g=", "path": "github.com/hashicorp/hcl/hcl/scanner", "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", "revisionTime": "2016-09-02T16:52:19Z" }, { "checksumSHA1": "JlZmnzqdmFFyb1+2afLyR3BOE/8=", "path": "github.com/hashicorp/hcl/hcl/strconv", "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", "revisionTime": "2016-09-02T16:52:19Z" }, { "checksumSHA1": "jQ45CCc1ed/nlV7bbSnx6z72q1M=", "path": "github.com/hashicorp/hcl/json/parser", "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", "revisionTime": "2016-09-02T16:52:19Z" }, { "checksumSHA1": "YdvFsNOMSWMLnY6fcliWQa0O5Fw=", "path": "github.com/hashicorp/hcl/json/scanner", "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", "revisionTime": "2016-09-02T16:52:19Z" }, { "checksumSHA1": "fNlXQCQEnb+B3k5UDL/r15xtSJY=", "path": "github.com/hashicorp/hcl/json/token", "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", "revisionTime": "2016-09-02T16:52:19Z" }, { "checksumSHA1": "0ZrwvB6KoGPj2PoDNSEJwxQ6Mog=", "origin": "github.com/aws/aws-sdk-go/vendor/github.com/jmespath/go-jmespath", "path": "github.com/jmespath/go-jmespath", "revision": "bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d", "revisionTime": "2016-08-03T19:07:31Z" } ], "rootPath": "github.com/saymedia/journald-cloudwatch-logs" } ================================================ FILE: writer.go ================================================ package main import ( "encoding/json" "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" awsSession "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" ) type Writer struct { conn *cloudwatchlogs.CloudWatchLogs logGroupName string logStreamName string nextSequenceToken string } func NewWriter(sess *awsSession.Session, logGroupName, logStreamName, firstSeqToken string) (*Writer, error) { conn := cloudwatchlogs.New(sess) return &Writer{ conn: conn, logGroupName: logGroupName, logStreamName: logStreamName, nextSequenceToken: firstSeqToken, }, nil } func (w *Writer) WriteBatch(records []Record) (string, error) { events := make([]*cloudwatchlogs.InputLogEvent, 0, len(records)) for _, record := range records { jsonDataBytes, err := json.MarshalIndent(record, "", " ") if err != nil { return "", err } jsonData := string(jsonDataBytes) events = append(events, &cloudwatchlogs.InputLogEvent{ Message: aws.String(jsonData), Timestamp: aws.Int64(int64(record.TimeUsec)), }) } putEvents := func() error { request := &cloudwatchlogs.PutLogEventsInput{ LogEvents: events, LogGroupName: &w.logGroupName, LogStreamName: &w.logStreamName, } if w.nextSequenceToken != "" { request.SequenceToken = aws.String(w.nextSequenceToken) } result, err := w.conn.PutLogEvents(request) if err != nil { return err } w.nextSequenceToken = *result.NextSequenceToken return nil } createStream := func() error { request := &cloudwatchlogs.CreateLogStreamInput{ LogGroupName: &w.logGroupName, LogStreamName: &w.logStreamName, } _, err := w.conn.CreateLogStream(request) return err } err := putEvents() if err != nil { if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "ResourceNotFoundException" { // Maybe our log stream doesn't exist yet. We'll try // to create it and then, if we're successful, try // writing the events again. err := createStream() if err != nil { return "", fmt.Errorf("failed to create stream: %s", err) } err = putEvents() if err != nil { return "", fmt.Errorf("failed to put events: %s", err) } return w.nextSequenceToken, nil } if awsErr.Code() == "DataAlreadyAcceptedException" { // This batch was already sent return "", nil } if awsErr.Code() == "InvalidSequenceTokenException" { request := &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: &w.logGroupName, LogStreamNamePrefix: &w.logStreamName, Descending: aws.Bool(true), Limit: aws.Int64(1), } result, err := w.conn.DescribeLogStreams(request) if err != nil { return "", fmt.Errorf("failed to get next sequence token: %s", err) } w.nextSequenceToken = *(result.LogStreams[0].UploadSequenceToken) err = putEvents() if err != nil { return "", fmt.Errorf("failed to put events: %s", err) } return w.nextSequenceToken, nil } } return "", fmt.Errorf("failed to put events: %s", err) } return w.nextSequenceToken, nil }