├── cmd └── scloud │ ├── cmd │ ├── scloud │ │ ├── version │ │ │ ├── .gitkeep │ │ │ └── client_info.go │ │ ├── main.go │ │ └── gen_version.go │ ├── root_test.go │ ├── ml │ │ └── ml.go │ ├── ingest │ │ └── ingest.go │ ├── version.go │ ├── identity │ │ └── identity.go │ ├── action │ │ └── action.go │ ├── forwarders │ │ ├── forwarders.go │ │ └── forwarders-gen.go │ ├── search │ │ └── search.go │ ├── catalog │ │ └── catalog.go │ ├── collect │ │ └── collect.go │ ├── kvstore │ │ └── kvstore.go │ ├── streams │ │ └── streams.go │ ├── provisioner │ │ ├── provisioner.go │ │ └── provisioner-gen.go │ ├── appregistry │ │ └── appregistry.go │ ├── login │ │ └── login.go │ └── context │ │ └── context.go │ ├── pkg │ ├── config │ │ └── config.go │ ├── ml │ │ └── ml.go │ ├── ingest │ │ ├── ingest.go │ │ └── ingest_non_generated_unit_test.go │ ├── search │ │ └── search.go │ ├── catalog │ │ └── catalog.go │ ├── collect │ │ └── collect.go │ ├── streams │ │ └── streams.go │ ├── identity │ │ └── identity.go │ ├── appregistry │ │ └── appregistry.go │ ├── forwarders │ │ ├── forwarders.go │ │ └── forwarders-gen.go │ ├── provisioner │ │ └── provisioner.go │ ├── action │ │ ├── action.go │ │ └── action-non-generated.go │ ├── kvstore │ │ └── kvstore.go │ └── login │ │ └── login.go │ ├── test │ ├── fixtures │ │ └── .test.context.env │ ├── testcases │ │ ├── test_stream_compile.spl │ │ ├── certfile.crt │ │ ├── test_stream_put_connection.json │ │ ├── test_stream_update_connection.json │ │ ├── forwarders_test │ │ ├── test_stream_create_connection.json │ │ ├── provisioner_test │ │ ├── test_stream_expand_pipeline.json │ │ ├── test_stream_get_input_schema.json │ │ ├── test_stream_get_output_schema.json │ │ ├── test_stream_create_pipeline.json │ │ ├── test_stream_merge_pipelines_inputtree.json │ │ ├── test_stream_merge_pipelines_maintree.json │ │ ├── test_stream_patch_pipeline.json │ │ ├── test_stream_validate_pipeline.json │ │ ├── search_test │ │ ├── action_test │ │ ├── provisioner_test.expected │ │ ├── test_forwarders_pem.pem │ │ ├── test_stream_create_group.json │ │ ├── kvstore_test │ │ ├── ingest_test │ │ ├── collect_test │ │ ├── forwarders_test.expected │ │ ├── identity_test │ │ ├── action_test.expected │ │ ├── search_test.expected │ │ ├── streams_test │ │ ├── appreg_test │ │ ├── kvstore_test.expected │ │ ├── collect_test.expected │ │ └── test_stream_create_template.json │ ├── test_ingest_event_json.log │ ├── test_ingest_event_raw.log │ ├── test_ingest_metric_json.log │ ├── usage_template_test.go │ ├── cli_test.go │ ├── utils │ │ ├── env-variables.go │ │ └── test_server.go │ └── record_result_test.go │ ├── jsonx │ └── pprint.go │ ├── util │ └── templates.go │ └── auth │ └── statik │ └── statik.go ├── CODEOWNERS ├── cicd ├── scripts │ ├── test_specific.sh │ ├── login_scloud.sh │ ├── token.sh │ └── build_cross_compile_scloud.sh ├── docs │ ├── docs.manifest.json │ ├── docs_md.sh │ └── publish.sh ├── integration │ ├── run_scloud_tests.sh │ ├── runexamples.sh │ └── runtests.sh ├── whitesource │ └── whitesource-fs-agent.config ├── unit_tests │ └── run_unit_tests.sh └── publish │ └── scloud │ └── publish_github.sh ├── .gitlab-ci.yml ├── .golangci.toml ├── services ├── client_info.go ├── search │ ├── service.go │ ├── interface.go │ └── iterator.go ├── action │ ├── model_sdk.go │ ├── interface.go │ └── service_sdk.go ├── ml │ └── interface.go ├── catalog │ └── interface.go ├── collect │ ├── interface.go │ └── param_generated.go ├── identity │ └── interface.go ├── kvstore │ ├── interface.go │ └── model_generated.go ├── streams │ ├── interface.go │ └── model_sdk.go ├── appregistry │ ├── interface.go │ └── param_generated.go ├── forwarders │ ├── interface.go │ ├── model_generated.go │ └── interface_generated.go ├── provisioner │ ├── interface.go │ ├── model_generated.go │ └── interface_generated.go └── ingest │ ├── param_generated.go │ ├── interface.go │ └── new_batch_events_sender.go ├── tools.go ├── copyright.txt ├── .gitignore ├── sonar-project.properties ├── sonar-project.properties.scloud ├── util ├── credential_unit_test.go ├── parse_templated_path.go ├── credential.go ├── logs.go ├── ticker.go ├── errors.go ├── ticker_unit_test.go ├── roundtripper.go ├── errors_unit_test.go └── gen_interface.go ├── test ├── integration │ ├── environment_integration_test.go │ └── provisioner_integration_test.go └── utils │ └── utils.go ├── CONTRIBUTING.md ├── examples ├── logging │ └── logging.go └── mock │ └── mock.go ├── sdk └── sdk.go └── idp └── idp_unit_test.go /cmd/scloud/cmd/scloud/version/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | -------------------------------------------------------------------------------- /cmd/scloud/test/fixtures/.test.context.env: -------------------------------------------------------------------------------- 1 | SCLOUD_CACHE_PATH = .test_scloud_context 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Team to use as reviewers for PRs of any files modified (*) 2 | * @splunk/devplat-seattle -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_compile.spl: -------------------------------------------------------------------------------- 1 | | from splunk_firehose() | into index("index", "main"); -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/certfile.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | FAKE_DATA 3 | -----END CERTIFICATE----- 4 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/ml/ml.go: -------------------------------------------------------------------------------- 1 | package ml 2 | 3 | //go:generate scloudgen gen-impl --name ml --package ml --output ml-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /cicd/scripts/test_specific.sh: -------------------------------------------------------------------------------- 1 | echo "To run a specific test:" 2 | echo " gotestsum --format short-verbose -- ./test/integration/... -run [pattern]" 3 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/ingest/ingest.go: -------------------------------------------------------------------------------- 1 | package ingest 2 | 3 | //go:generate scloudgen gen-impl --name ingest --package ingest --output ingest-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/search/search.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | //go:generate scloudgen gen-impl --name search --package search --output search-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/catalog/catalog.go: -------------------------------------------------------------------------------- 1 | package catalog 2 | 3 | //go:generate scloudgen gen-impl --name catalog --package catalog --output catalog-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/collect/collect.go: -------------------------------------------------------------------------------- 1 | package collect 2 | 3 | //go:generate scloudgen gen-impl --name collect --package collect --output collect-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/streams/streams.go: -------------------------------------------------------------------------------- 1 | package streams 2 | 3 | //go:generate scloudgen gen-impl --name streams --package streams --output streams-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/identity/identity.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | //go:generate scloudgen gen-impl --name identity --package identity --output identity-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - project: 'devplat-pr-32/gitlab-central' 3 | ref: '7b525322aa5c0e3dc92111cd29dcef07ce4841f4' 4 | file: '/splunk-cloud-sdk-go/.gitlab-ci.yml' -------------------------------------------------------------------------------- /cmd/scloud/pkg/appregistry/appregistry.go: -------------------------------------------------------------------------------- 1 | package appregistry 2 | 3 | //go:generate scloudgen gen-impl --name app-registry --package appreg --output appreg-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/forwarders/forwarders.go: -------------------------------------------------------------------------------- 1 | package forwarders 2 | 3 | //go:generate scloudgen gen-impl --name forwarders --package forwarders --output forwarders-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /.golangci.toml: -------------------------------------------------------------------------------- 1 | [run] 2 | concurrency = 4 3 | deadline = "90s" 4 | issues-exit-code = 1 5 | 6 | [linters] 7 | enable = [ 8 | "govet", 9 | "goimports", 10 | "gofmt" 11 | ] -------------------------------------------------------------------------------- /cmd/scloud/pkg/provisioner/provisioner.go: -------------------------------------------------------------------------------- 1 | package provisioner 2 | 3 | //go:generate scloudgen gen-impl --name provisioner --package provisioner --output provisioner-gen.go | gofmt 4 | -------------------------------------------------------------------------------- /cicd/docs/docs.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "category": "sdks", 3 | "name": "Splunk Cloud SDK for Go", 4 | "description": "A SDK in Go for making requests to Splunk Cloud hosted services." 5 | } -------------------------------------------------------------------------------- /services/client_info.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | // Version the released version of the SDK 4 | 5 | const Version = "1.12.0-beta.8" 6 | 7 | // UserAgent SDK Client Identifier 8 | const UserAgent = "client-go" 9 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_put_connection.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "newname", 3 | "data": { 4 | "splunk-url":"https://hostname.port", 5 | "token":"mytoken"}, 6 | "description": "A new connection" 7 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_update_connection.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "newname", 3 | "data": { 4 | "splunk-url":"https://hostname.port", 5 | "token":"mytoken"}, 6 | "description": "A new connection" 7 | } -------------------------------------------------------------------------------- /tools.go: -------------------------------------------------------------------------------- 1 | // +build tools 2 | 3 | package tools 4 | 5 | import ( 6 | _ "github.com/golangci/golangci-lint/cmd/golangci-lint" 7 | _ "golang.org/x/tools/cmd/goimports" 8 | _ "gotest.tools/gotestsum" 9 | ) 10 | -------------------------------------------------------------------------------- /cmd/scloud/test/test_ingest_event_json.log: -------------------------------------------------------------------------------- 1 | {"body":{"event":"199.72.81.55 - - [01/Jul/1995:00:00:01 -0400] \"GET /history/apollo/ HTTP/1.0\" 200 6245"},"host":"scloud_test_ingest_host","source":"scloud_test_ingest_source"} 2 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/forwarders_test: -------------------------------------------------------------------------------- 1 | forwarders add-certificate --input-datafile testcases/test_forwarders_pem.pem 2 | forwarders list-certificates 3 | forwarders delete-certificate --slot 1 4 | forwarders delete-certificates 5 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/scloud/version/client_info.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // Version the released version of the SDK 4 | 5 | const ScloudVersion = "8.0.0-beta.8" 6 | 7 | // UserAgent Scloud Client Identifier 8 | const UserAgent = "scloud" 9 | -------------------------------------------------------------------------------- /cmd/scloud/test/test_ingest_event_raw.log: -------------------------------------------------------------------------------- 1 | event1: 199.72.81.55 - - [01/Jul/1995:00:00:01 -0400] "GET /history/apollo/ HTTP/1.0" 200 6245 2 | event2: unicomp6.unicomp.net - - [01/Jul/1995:00:00:06 -0400] "GET /shuttle/countdown/ HTTP/1.0" 200 3985 3 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/action/action.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | //go:generate scloudgen gen-impl --name action --package action --output action-gen.go | gofmt 4 | 5 | //create service object here. and you can use it in template to invoke the api call? 6 | //svc.createTenant(sdfsdf) 7 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/scloud/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:generate go run gen_version.go 4 | 5 | import ( 6 | "github.com/golang/glog" 7 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/cmd" 8 | ) 9 | 10 | func main() { 11 | cmd.Execute() 12 | glog.Flush() 13 | } 14 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/kvstore/kvstore.go: -------------------------------------------------------------------------------- 1 | package kvstore 2 | 3 | //go:generate scloudgen gen-impl --name kvstore --package kvstore --output kvstore-gen.go | gofmt 4 | 5 | //create service object here. and you can use it in template to invoke the api call? 6 | //svc.createTenant(sdfsdf) 7 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_create_connection.json: -------------------------------------------------------------------------------- 1 | { 2 | "connectorId": "879837b0-cabf-4bc2-8589-fcc4dad753e7", 3 | "data": { 4 | "splunk-url": "https://hostname.port", 5 | "token": "mytoken" 6 | }, 7 | "description": "", 8 | "name": "testConnection1582068774" 9 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/provisioner_test: -------------------------------------------------------------------------------- 1 | provisioner create-invite --email aa@splunk.com 2 | provisioner get-invite --invite-id i5e603d1366957b00069575fe 3 | provisioner list-invites 4 | provisioner delete-invite --invite-id i5e603d1366957b00069575fe 5 | provisioner list-tenants 6 | provisioner update-invite --invite-id i5e603d9225fe920006b12c8e --action accept 7 | -------------------------------------------------------------------------------- /cmd/scloud/test/test_ingest_metric_json.log: -------------------------------------------------------------------------------- 1 | [{"name":"scloud_test_metric_name1","dimensions":{"scloud_test_metric_dimension_key1":"scloud_test_metric_dimension_value1"},"unit":"scloud_test_metric_unit1","value": 100},{"name":"scloud_test_metric_name2","dimensions":{"scloud_test_metric_dimension_key2":"scloud_test_metric_dimension_value2"},"type":"scloud_test_metric_type2","value":20},{"name":"scloud_test_metric_name3","unit":"scloud_test_metric_unit3","value":45}] 2 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/root_test.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestMain(m *testing.M) { 12 | // Setup 13 | // Now run all of our tests 14 | os.Exit(m.Run()) 15 | } 16 | 17 | func TestCmd(t *testing.T) { 18 | buf := new(bytes.Buffer) 19 | rootCmd.SetOutput(buf) 20 | rootCmd.SetArgs([]string{ 21 | "help", 22 | }) 23 | err := rootCmd.Execute() 24 | assert.Nil(t, err) 25 | } 26 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/action/action-non-generated.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/auth" 5 | model "github.com/splunk/splunk-cloud-sdk-go/services/action" 6 | ) 7 | 8 | // TriggerActionOverride 9 | func TriggerActionOverride(actionName string, body model.TriggerEvent) (*model.TriggerResponse, error) { 10 | 11 | client, err := auth.GetClient() 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | return client.ActionService.TriggerActionWithStatus(actionName, body) 17 | } 18 | -------------------------------------------------------------------------------- /copyright.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2019 Splunk, Inc. 2 | Licensed under the Apache License, Version 2.0 (the "License"): you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 5 | Unless required by applicable law or agreed to in writing, software 6 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 7 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 8 | License for the specific language governing permissions and limitations 9 | under the License. 10 | -------------------------------------------------------------------------------- /services/search/service.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Splunk Search Service 3 | * 4 | */ 5 | 6 | package search 7 | 8 | import "time" 9 | 10 | // WaitForJob polls the job until it's completed or errors out 11 | func (s *Service) WaitForJob(jobID string, pollInterval time.Duration) (interface{}, error) { 12 | for { 13 | job, err := s.GetJob(jobID) 14 | if err != nil { 15 | return nil, err 16 | } 17 | // wait for terminal state 18 | switch *job.Status { 19 | case SearchStatusDone, SearchStatusFailed, SearchStatusCanceled: 20 | return *job.Status, nil 21 | default: 22 | time.Sleep(pollInterval) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/ml/ml.go: -------------------------------------------------------------------------------- 1 | package ml 2 | 3 | ////go:generate scloudgen gen-cmd --name ml --package ml --output ml-gen.go | gofmt 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return mlCmd 13 | } 14 | 15 | var mlCmd = &cobra.Command{ 16 | Use: "ml", 17 | Short: "Machine Learning service", 18 | Run: func(cmd *cobra.Command, args []string) { 19 | _ = cmd.Usage() 20 | }, 21 | } 22 | 23 | func init() { 24 | mlCmd.SetUsageTemplate(usageUtil.UsageTemplate) 25 | mlCmd.SetHelpTemplate(usageUtil.HelpTemplate) 26 | } 27 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/ingest/ingest.go: -------------------------------------------------------------------------------- 1 | package ingest 2 | 3 | ////go:generate scloudgen gen-cmd --name ingest --package ingest --output ingest-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return ingestCmd 13 | } 14 | 15 | var ingestCmd = &cobra.Command{ 16 | Use: "ingest", 17 | Short: "Ingest service", 18 | Run: func(cmd *cobra.Command, args []string) { 19 | _ = cmd.Usage() 20 | }, 21 | } 22 | 23 | func init() { 24 | ingestCmd.SetUsageTemplate(usageUtil.UsageTemplate) 25 | ingestCmd.SetHelpTemplate(usageUtil.HelpTemplate) 26 | } 27 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/cmd/scloud/version" 8 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/jsonx" 9 | ) 10 | 11 | // versionCmd represents the version command 12 | var versionCmd = &cobra.Command{ 13 | Use: "version", 14 | Short: "Version of Splunk Cloud Services CLI", 15 | RunE: execVersionCmd, 16 | } 17 | 18 | func init() { 19 | rootCmd.AddCommand(versionCmd) 20 | } 21 | 22 | func execVersionCmd(cmd *cobra.Command, args []string) error { 23 | 24 | err := fmt.Sprintf("scloud version %s\n", version.Version) 25 | jsonx.Pprint(cmd, err) 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | .DS_Store 14 | 15 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 16 | .glide/ 17 | 18 | # Goland 19 | .idea/ 20 | debug 21 | *.iml 22 | .vscode/ 23 | 24 | vendor 25 | .vendor-new 26 | *.env 27 | tmp/ 28 | 29 | # used by token fetcher 30 | .token 31 | 32 | # Docs/build info 33 | cicd/docs/node_modules 34 | cicd/docs/build 35 | cicd/docs/package.json 36 | docs/ 37 | 38 | # scloud 39 | bin 40 | default.yaml 41 | cmd/scloud/cmd/scloud/version/version.go 42 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/identity/identity.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | ////go:generate scloudgen gen-cmd --name identity --package identity --output identity-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return identityCmd 13 | } 14 | 15 | var identityCmd = &cobra.Command{ 16 | Use: "identity", 17 | Short: "Identity service", 18 | Run: func(cmd *cobra.Command, args []string) { 19 | _ = cmd.Usage() 20 | }, 21 | } 22 | 23 | func init() { 24 | identityCmd.SetUsageTemplate(usageUtil.UsageTemplate) 25 | identityCmd.SetHelpTemplate(usageUtil.HelpTemplate) 26 | } 27 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/action/action.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | ////go:generate scloudgen gen-cmd --name action --package action --output action-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return actionCmd 13 | } 14 | 15 | // actionCmd represents the Action command 16 | var actionCmd = &cobra.Command{ 17 | Use: "action", 18 | Short: "Action service", 19 | Run: func(cmd *cobra.Command, args []string) { 20 | _ = cmd.Usage() 21 | }, 22 | } 23 | 24 | func init() { 25 | actionCmd.SetUsageTemplate(usageUtil.UsageTemplate) 26 | actionCmd.SetHelpTemplate(usageUtil.HelpTemplate) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/forwarders/forwarders.go: -------------------------------------------------------------------------------- 1 | package forwarders 2 | 3 | ////go:generate scloudgen gen-cmd --name forwarders --package forwarders --output forwarders-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return forwardersCmd 13 | } 14 | 15 | var forwardersCmd = &cobra.Command{ 16 | Use: "forwarders", 17 | Short: "Forwarders service", 18 | Run: func(cmd *cobra.Command, args []string) { 19 | _ = cmd.Usage() 20 | }, 21 | } 22 | 23 | func init() { 24 | forwardersCmd.SetUsageTemplate(usageUtil.UsageTemplate) 25 | forwardersCmd.SetHelpTemplate(usageUtil.HelpTemplate) 26 | } 27 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/search/search.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | ////go:generate scpgen gen-cmd --name search --package search --output search-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return searchCmd 13 | } 14 | 15 | // searchCmd represents the search command 16 | var searchCmd = &cobra.Command{ 17 | Use: "search", 18 | Short: "Search service", 19 | Run: func(cmd *cobra.Command, args []string) { 20 | _ = cmd.Usage() 21 | }, 22 | } 23 | 24 | func init() { 25 | searchCmd.SetUsageTemplate(usageUtil.UsageTemplate) 26 | searchCmd.SetHelpTemplate(usageUtil.HelpTemplate) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/catalog/catalog.go: -------------------------------------------------------------------------------- 1 | package catalog 2 | 3 | ////go:generate scloudgen gen-cmd --name catalog --package catalog --output catalog-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return catalogCmd 13 | } 14 | 15 | // catalogCmd represents the catalog command 16 | var catalogCmd = &cobra.Command{ 17 | Use: "catalog", 18 | Short: "Catalog service", 19 | Run: func(cmd *cobra.Command, args []string) { 20 | _ = cmd.Usage() 21 | }, 22 | } 23 | 24 | func init() { 25 | catalogCmd.SetUsageTemplate(usageUtil.UsageTemplate) 26 | catalogCmd.SetHelpTemplate(usageUtil.HelpTemplate) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/collect/collect.go: -------------------------------------------------------------------------------- 1 | package collect 2 | 3 | ////go:generate scloudgen gen-cmd --name collect --package collect --output collect-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return collectCmd 13 | } 14 | 15 | // collectCmd represents the collect command 16 | var collectCmd = &cobra.Command{ 17 | Use: "collect", 18 | Short: "Collect service", 19 | Run: func(cmd *cobra.Command, args []string) { 20 | _ = cmd.Usage() 21 | }, 22 | } 23 | 24 | func init() { 25 | collectCmd.SetUsageTemplate(usageUtil.UsageTemplate) 26 | collectCmd.SetHelpTemplate(usageUtil.HelpTemplate) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/kvstore/kvstore.go: -------------------------------------------------------------------------------- 1 | package kvstore 2 | 3 | ////go:generate scloudgen gen-cmd --name action --package action --output action-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return kvstoreCmd 13 | } 14 | 15 | // kvstoreCmd represents the KVStore command 16 | var kvstoreCmd = &cobra.Command{ 17 | Use: "kvstore", 18 | Short: "KV Store service", 19 | Run: func(cmd *cobra.Command, args []string) { 20 | _ = cmd.Usage() 21 | }, 22 | } 23 | 24 | func init() { 25 | kvstoreCmd.SetUsageTemplate(usageUtil.UsageTemplate) 26 | kvstoreCmd.SetHelpTemplate(usageUtil.HelpTemplate) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/streams/streams.go: -------------------------------------------------------------------------------- 1 | package streams 2 | 3 | ////go:generate scloudgen gen-cmd --name streams --package streams --output streams-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return streamsCmd 13 | } 14 | 15 | // streamsCmd represents the streams command 16 | var streamsCmd = &cobra.Command{ 17 | Use: "streams", 18 | Short: "Streams service", 19 | Run: func(cmd *cobra.Command, args []string) { 20 | _ = cmd.Usage() 21 | }, 22 | } 23 | 24 | func init() { 25 | streamsCmd.SetUsageTemplate(usageUtil.UsageTemplate) 26 | streamsCmd.SetHelpTemplate(usageUtil.HelpTemplate) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/provisioner/provisioner.go: -------------------------------------------------------------------------------- 1 | package provisioner 2 | 3 | ////go:generate scloudgen gen-cmd --name provisioner --package provisioner --output provisioner-gen.go | gofmt 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return provisionerCmd 13 | } 14 | 15 | var provisionerCmd = &cobra.Command{ 16 | Use: "provisioner", 17 | Short: "Provisioner service", 18 | Run: func(cmd *cobra.Command, args []string) { 19 | _ = cmd.Usage() 20 | }, 21 | } 22 | 23 | func init() { 24 | provisionerCmd.SetUsageTemplate(usageUtil.UsageTemplate) 25 | provisionerCmd.SetHelpTemplate(usageUtil.HelpTemplate) 26 | } 27 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/appregistry/appregistry.go: -------------------------------------------------------------------------------- 1 | package appregistry 2 | 3 | ////go:generate scloudgen gen-cmd --name app-registry --package appreg --output appreg-gen.go 4 | 5 | import ( 6 | "github.com/spf13/cobra" 7 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 8 | ) 9 | 10 | // Cmd -- used to connection to rootCmd 11 | func Cmd() *cobra.Command { 12 | return appregistryCmd 13 | } 14 | 15 | // appregistryCmd represents the App Registry command 16 | var appregistryCmd = &cobra.Command{ 17 | Use: "appreg", 18 | Short: "App Registry service", 19 | Run: func(cmd *cobra.Command, args []string) { 20 | _ = cmd.Usage() 21 | }, 22 | } 23 | 24 | func init() { 25 | appregistryCmd.SetUsageTemplate(usageUtil.UsageTemplate) 26 | appregistryCmd.SetHelpTemplate(usageUtil.HelpTemplate) 27 | } 28 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | # unique project key, usually your project name 2 | sonar.projectKey=splunk-cloud-sdk-go 3 | sonar.projectName=Splunk Cloud SDK for Go 4 | # define the directories to scan 5 | sonar.sources=. 6 | # define the files not to analyze for scanning 7 | sonar.exclusions=cmd/**,**/*_test.go,**/vendor/**,**/*.yaml,**/*.py 8 | sonar.tests=. 9 | sonar.test.inclusions=**/*_test.go 10 | sonar.test.exclusions=cmd/**/*_test.go,**/vendor/** 11 | # The file that the sonarqube scanner imports for coverage differs per language, 12 | # please refer to sonarqube docs on how to configure the path for your language 13 | # https://docs.sonarqube.org/display/PLUG/SonarSource+Plugins 14 | # For Go: https://docs.sonarqube.org/display/PLUG/Go+Coverage+Results+Import 15 | sonar.typescript.lcov.reportPaths=coverage-unit/coverage.out,coverage-integration/coverage.out,coverage-integration-ml/coverage.out 16 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_expand_pipeline.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "e3f9eb13-a847-4717-9f83-89c815b03d01", 5 | "sourcePort": "output", 6 | "targetNode": "6f14bd4d-e299-4677-b5db-441b40acd501", 7 | "targetPort": "input" 8 | } 9 | ], 10 | "nodes": [ 11 | { 12 | "attributes": {}, 13 | "id": "e3f9eb13-a847-4717-9f83-89c815b03d01", 14 | "op": "read-splunk-firehose", 15 | "resolvedId": "read-splunk-firehose" 16 | }, 17 | { 18 | "attributes": {}, 19 | "dataset": "dataset:main", 20 | "id": "6f14bd4d-e299-4677-b5db-441b40acd501", 21 | "module": "module:index", 22 | "op": "write-index", 23 | "resolvedId": "write-index:collection>:expression:expression" 24 | } 25 | ], 26 | "rootNode": [ 27 | "6f14bd4d-e299-4677-b5db-441b40acd501" 28 | ] 29 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_get_input_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "1df22bab-8d0d-44c3-ad8a-f3ba1b85ff84", 5 | "sourcePort": "output", 6 | "targetNode": "3682041e-1814-4bd7-8e60-5c889b822585", 7 | "targetPort": "input" 8 | } 9 | ], 10 | "nodes": [ 11 | { 12 | "attributes": {}, 13 | "id": "1df22bab-8d0d-44c3-ad8a-f3ba1b85ff84", 14 | "op": "read-splunk-firehose", 15 | "resolvedId": "read-splunk-firehose" 16 | }, 17 | { 18 | "attributes": {}, 19 | "dataset": "dataset:main", 20 | "id": "3682041e-1814-4bd7-8e60-5c889b822585", 21 | "module": "module:index", 22 | "op": "write-index", 23 | "resolvedId": "write-index:collection>:expression:expression" 24 | } 25 | ], 26 | "rootNode": [ 27 | "3682041e-1814-4bd7-8e60-5c889b822585" 28 | ] 29 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_get_output_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "1df22bab-8d0d-44c3-ad8a-f3ba1b85ff84", 5 | "sourcePort": "output", 6 | "targetNode": "3682041e-1814-4bd7-8e60-5c889b822585", 7 | "targetPort": "input" 8 | } 9 | ], 10 | "nodes": [ 11 | { 12 | "attributes": {}, 13 | "id": "1df22bab-8d0d-44c3-ad8a-f3ba1b85ff84", 14 | "op": "read-splunk-firehose", 15 | "resolvedId": "read-splunk-firehose" 16 | }, 17 | { 18 | "attributes": {}, 19 | "dataset": "dataset:main", 20 | "id": "3682041e-1814-4bd7-8e60-5c889b822585", 21 | "module": "module:index", 22 | "op": "write-index", 23 | "resolvedId": "write-index:collection>:expression:expression" 24 | } 25 | ], 26 | "rootNode": [ 27 | "3682041e-1814-4bd7-8e60-5c889b822585" 28 | ] 29 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_create_pipeline.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "c0edd974-1190-3f73-923a-4330a5bc2a7c", 5 | "sourcePort": "output", 6 | "targetNode": "6defeeb3-a0d1-386f-897b-7cff5fe2ce34", 7 | "targetPort": "input" 8 | } 9 | ], 10 | "nodes": [ 11 | { 12 | "id": "c0edd974-1190-3f73-923a-4330a5bc2a7c", 13 | "op": "from_splunk_firehose", 14 | "resolvedId": "from_splunk_firehose" 15 | }, 16 | { 17 | "id": "6defeeb3-a0d1-386f-897b-7cff5fe2ce34", 18 | "op": "into_index", 19 | "arguments": { 20 | "dataset": "\"main\"", 21 | "module": "\"index\"" 22 | }, 23 | "resolvedId": "into_index:collection\u003crecord\u003cR\u003e\u003e:expression\u003cstring\u003e:expression\u003cstring\u003e" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_merge_pipelines_inputtree.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "00ba387b-a219-4f68-b3a8-8b99df379dd6", 5 | "sourcePort": "output", 6 | "targetNode": "fbe6269f-30d3-4922-be6c-84a9f2b84bb3", 7 | "targetPort": "input" 8 | } 9 | ], 10 | "nodes": [ 11 | { 12 | "attributes": {}, 13 | "id": "00ba387b-a219-4f68-b3a8-8b99df379dd6", 14 | "op": "read-splunk-firehose", 15 | "resolvedId": "read-splunk-firehose" 16 | }, 17 | { 18 | "attributes": {}, 19 | "dataset": "dataset:main", 20 | "id": "fbe6269f-30d3-4922-be6c-84a9f2b84bb3", 21 | "module": "module:index", 22 | "op": "write-index", 23 | "resolvedId": "write-index:collection>:expression:expression" 24 | } 25 | ], 26 | "rootNode": [ 27 | "fbe6269f-30d3-4922-be6c-84a9f2b84bb3" 28 | ] 29 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_merge_pipelines_maintree.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "97cfd7ee-f744-43d9-8338-2e164ebecf91", 5 | "sourcePort": "output", 6 | "targetNode": "9e6dec08-9658-46be-914b-fc872d9b7828", 7 | "targetPort": "input" 8 | } 9 | ], 10 | "nodes": [ 11 | { 12 | "attributes": {}, 13 | "id": "97cfd7ee-f744-43d9-8338-2e164ebecf91", 14 | "op": "read-splunk-firehose", 15 | "resolvedId": "read-splunk-firehose" 16 | }, 17 | { 18 | "attributes": {}, 19 | "dataset": "dataset:main", 20 | "id": "9e6dec08-9658-46be-914b-fc872d9b7828", 21 | "module": "module:index", 22 | "op": "write-index", 23 | "resolvedId": "write-index:collection>:expression:expression" 24 | } 25 | ], 26 | "rootNode": [ 27 | "9e6dec08-9658-46be-914b-fc872d9b7828" 28 | ] 29 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_patch_pipeline.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "c0edd974-1190-3f73-923a-4330a5bc2a7c", 5 | "sourcePort": "output", 6 | "targetNode": "6defeeb3-a0d1-386f-897b-7cff5fe2ce34", 7 | "targetPort": "input" 8 | } 9 | ], 10 | "nodes": [ 11 | { 12 | "id": "c0edd974-1190-3f73-923a-4330a5bc2a7c", 13 | "op": "from_splunk_firehose", 14 | "resolvedId": "from_splunk_firehose" 15 | }, 16 | { 17 | "id": "6defeeb3-a0d1-386f-897b-7cff5fe2ce34", 18 | "op": "into_index", 19 | "arguments": { 20 | "dataset": "\"main\"", 21 | "module": "\"index\"" 22 | }, 23 | "resolvedId": "into_index:collection\u003crecord\u003cR\u003e\u003e:expression\u003cstring\u003e:expression\u003cstring\u003e" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_validate_pipeline.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "c0edd974-1190-3f73-923a-4330a5bc2a7c", 5 | "sourcePort": "output", 6 | "targetNode": "6defeeb3-a0d1-386f-897b-7cff5fe2ce34", 7 | "targetPort": "input" 8 | } 9 | ], 10 | "nodes": [ 11 | { 12 | "id": "c0edd974-1190-3f73-923a-4330a5bc2a7c", 13 | "op": "from_splunk_firehose", 14 | "resolvedId": "from_splunk_firehose" 15 | }, 16 | { 17 | "id": "6defeeb3-a0d1-386f-897b-7cff5fe2ce34", 18 | "op": "into_index", 19 | "arguments": { 20 | "dataset": "\"main\"", 21 | "module": "\"index\"" 22 | }, 23 | "resolvedId": "into_index:collection\u003crecord\u003cR\u003e\u003e:expression\u003cstring\u003e:expression\u003cstring\u003e" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/search_test: -------------------------------------------------------------------------------- 1 | search create-job --query "from index:main" 2 | search create-job --query "from index:main" --allow-side-effects true --collect-event-summary true --collect-field-summary true --collect-time-buckets true --enable-preview true 3 | search get-job --sid f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll 4 | search list-jobs 5 | search list-results --sid f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll 6 | search update-job --sid f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll --status finalized 7 | search list-events-summary --sid "0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn" 8 | search list-fields-summary --sid "0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn" 9 | search list-preview-results --sid "0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn" 10 | search list-time-buckets --sid "0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn" 11 | -------------------------------------------------------------------------------- /sonar-project.properties.scloud: -------------------------------------------------------------------------------- 1 | # unique project key, usually your project name 2 | sonar.projectKey=scloud 3 | sonar.projectName=Splunk Cloud CLI 4 | # define the directories to scan - need to include all src files to show coverage of 5 | # splunk-cloud-sdk-go api endpoints for scloud tests 6 | sonar.sources=. 7 | # define the files not to analyze for scanning 8 | sonar.exclusions=**/*_test.go,**/vendor/**,**/*.yaml,**/*.py 9 | sonar.tests=. 10 | sonar.test.inclusions=cmd/**/*_test.go 11 | sonar.test.exclusions=**/vendor/** 12 | # The file that the sonarqube scanner imports for coverage differs per language, 13 | # please refer to sonarqube docs on how to configure the path for your language 14 | # https://docs.sonarqube.org/display/PLUG/SonarSource+Plugins 15 | # For Go: https://docs.sonarqube.org/display/PLUG/Go+Coverage+Results+Import 16 | sonar.typescript.lcov.reportPaths=coverage-unit/coverage.out,coverage-integration-scloud/coverage.out 17 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/action_test: -------------------------------------------------------------------------------- 1 | action create-action-email --name scloud_test_action_test --members kk@splunk.com --members aa@splunk.com 2 | action update-action-email-mutable --action-name scloud_test_action_test --subject "newsubject" 3 | action get-action --action-name scloud_test_action_test 4 | 5 | action get-public-webhook-keys 6 | 7 | action create-action-webhook --name scloud_test_action_test_wh --title newtitle --webhook-payload "{{ .name }} is a {{ .species }}" --webhook-url "https://webhook.site/test" 8 | action update-action-webhook-mutable --action-name scloud_test_action_test_wh --title "newtitle" 9 | 10 | action trigger-action --action-name scloud_test_action_test_wh 11 | action get-action-status --action-name scloud_test_action_test --status-id CN4uIrr8qsmBVzkhlg0niUs39euOr6Jb 12 | 13 | action list-actions 14 | 15 | action delete-action --action-name scloud_test_action_test 16 | action delete-action --action-name scloud_test_action_test_wh 17 | -------------------------------------------------------------------------------- /services/action/model_sdk.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | // This files contains models that can't be auto-generated from codegen 18 | package action 19 | 20 | import "net/url" 21 | 22 | // TriggerResponse for returning status url and parsed statusID (if possible) 23 | type TriggerResponse struct { 24 | StatusID *string 25 | StatusURL *url.URL 26 | } 27 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/provisioner_test.expected: -------------------------------------------------------------------------------- 1 | #testcase: provisioner create-invite --email aa@splunk.com 2 | REQUEST URL:provisioner/v1beta1/invites 3 | REQUEST BODY:{{"email":"aa@splunk.com"}} 4 | 5 | #testcase: provisioner get-invite --invite-id i5e603d1366957b00069575fe 6 | REQUEST URL:provisioner/v1beta1/invites/i5e603d1366957b00069575fe 7 | REQUEST BODY: 8 | 9 | #testcase: provisioner list-invites 10 | REQUEST URL:provisioner/v1beta1/invites 11 | REQUEST BODY: 12 | 13 | #testcase: provisioner delete-invite --invite-id i5e603d1366957b00069575fe 14 | REQUEST URL:provisioner/v1beta1/invites/i5e603d1366957b00069575fe 15 | REQUEST BODY: 16 | 17 | #testcase: provisioner list-tenants 18 | REQUEST URL:provisioner/v1beta1/tenants 19 | REQUEST BODY: 20 | 21 | #testcase: provisioner update-invite --invite-id i5e603d9225fe920006b12c8e --action accept 22 | REQUEST URL:provisioner/v1beta1/invites/i5e603d9225fe920006b12c8e 23 | REQUEST BODY:{{"action":"accept"}} 24 | 25 | -------------------------------------------------------------------------------- /util/credential_unit_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func TestCredentialOutputRedactedString(t *testing.T) { 27 | pw := NewCredential("mypassword") 28 | assert.Equal(t, fmt.Sprintf("%s", pw), "XXXXX") 29 | assert.Equal(t, fmt.Sprintf("%s", pw.ClearText()), "mypassword") 30 | } 31 | -------------------------------------------------------------------------------- /services/ml/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package ml 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /services/catalog/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package catalog 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /services/collect/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package collect 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /services/identity/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package identity 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /services/kvstore/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package kvstore 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /services/streams/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package streams 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /services/appregistry/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package appregistry 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /services/forwarders/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package forwarders 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /services/provisioner/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package provisioner 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that are auto-generated in interface_generated.go 24 | ServicerGenerated 25 | } 26 | -------------------------------------------------------------------------------- /cmd/scloud/test/usage_template_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | utils "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/test/utils" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestServiceCmdShouldReturnShortUsage(t *testing.T) { 12 | command := "action" 13 | _, err, std := utils.ExecuteCmd(command, t) 14 | 15 | assert.Equal(t, nil, err) 16 | 17 | isShortUsage := !strings.Contains(std, "Global Flags:") 18 | assert.Equal(t, true, isShortUsage) 19 | } 20 | 21 | func TestRootCmdShouldReturnShortUsage(t *testing.T) { 22 | command := "" 23 | _, err, std := utils.ExecuteCmd(command, t) 24 | 25 | assert.Equal(t, nil, err) 26 | 27 | isShortUsage := !strings.Contains(std, "Global Flags:") 28 | assert.Equal(t, true, isShortUsage) 29 | } 30 | 31 | func TestHelpFlagShouldLongUsage(t *testing.T) { 32 | command := "action --help" 33 | res, err, _ := utils.ExecuteCmd(command, t) 34 | 35 | assert.Equal(t, nil, err) 36 | 37 | isLongUsage := strings.Contains(res, "Global Flags:") 38 | assert.Equal(t, true, isLongUsage) 39 | } 40 | -------------------------------------------------------------------------------- /test/integration/environment_integration_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package integration 18 | 19 | import ( 20 | "testing" 21 | 22 | testutils "github.com/splunk/splunk-cloud-sdk-go/test/utils" 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func TestIntegrationEnvironment(t *testing.T) { 27 | assert.NotEmpty(t, testutils.TestAuthenticationToken) 28 | assert.NotEmpty(t, testutils.TestSplunkCloudHost) 29 | assert.NotEmpty(t, testutils.TestTenant) 30 | } 31 | -------------------------------------------------------------------------------- /cicd/scripts/login_scloud.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # login to system 4 | ./bin/scloud config set --key env --value $TEST_ENVIRONMENT_1 5 | ./bin/scloud config set --key username --value $TEST_USERNAME 6 | ./bin/scloud config set --key tenant --value system 7 | ./bin/scloud config set --key tenant-scoped --value "true" 8 | ./bin/scloud config set --key region --value $REGION 9 | ./bin/scloud login --use-pkce --pwd $TEST_PASSWORD 10 | # also login to test tenant 11 | ./bin/scloud config set --key tenant --value $TEST_TENANT_SCOPED 12 | ./bin/scloud login --use-pkce --pwd $TEST_PASSWORD 13 | 14 | # Cross-platform sed -i: https://stackoverflow.com/a/38595160 15 | sedi () { 16 | sed --version >/dev/null 2>&1 && sed -i -- "$@" || sed -i "" "$@" 17 | } 18 | 19 | touch .env 20 | 21 | if grep -q '^SCLOUD_CACHE_PATH=' .env; then 22 | if sedi "s/SCLOUD_CACHE_PATH=.*/SCLOUD_CACHE_PATH=.scloud_context/" .env; then 23 | echo "SCLOUD_CACHE_PATH updated in .env" 24 | fi 25 | else 26 | if echo "SCLOUD_CACHE_PATH=.scloud_context" | tee -a .env >/dev/null; then 27 | echo "SCLOUD_CACHE_PATH written to .env" 28 | fi 29 | fi 30 | -------------------------------------------------------------------------------- /cmd/scloud/jsonx/pprint.go: -------------------------------------------------------------------------------- 1 | package jsonx 2 | 3 | import ( 4 | "encoding/json" 5 | "strings" 6 | 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | func pprint(cmd *cobra.Command, value interface{}, asErr bool) { 11 | if value == nil { 12 | return 13 | } 14 | switch vt := value.(type) { 15 | case string: 16 | if asErr { 17 | cmd.PrintErr(vt) 18 | } else { 19 | cmd.Print(vt) 20 | } 21 | if !strings.HasSuffix(vt, "\n") { 22 | if asErr { 23 | cmd.PrintErrln() 24 | } else { 25 | cmd.Println() 26 | } 27 | } 28 | default: 29 | var encoder *json.Encoder 30 | if asErr { 31 | encoder = json.NewEncoder(cmd.OutOrStderr()) 32 | } else { 33 | encoder = json.NewEncoder(cmd.OutOrStdout()) 34 | } 35 | encoder.SetIndent("", " ") 36 | err := encoder.Encode(value) 37 | if err != nil { 38 | panic("jsonx.pprint: encoder.Encode(value) error: %s" + err.Error()) 39 | } 40 | } 41 | } 42 | 43 | func Pprint(cmd *cobra.Command, value interface{}) { 44 | pprint(cmd, value, false) 45 | } 46 | 47 | func PprintErr(cmd *cobra.Command, value interface{}) { 48 | pprint(cmd, value, true) 49 | } 50 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_forwarders_pem.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC1TCCAb2gAwIBAgIJAIOAwz2qyz1FMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV 3 | BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0yMTA4MjcxOTAwNTVaFw0yNjA4MjYxOTAw 4 | NTVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB 5 | BQADggEPADCCAQoCggEBANHY9Uc+AJL17z6GkJ9VoiPU0TDF3+rVjp2CLxcc2Upt 6 | BgX//F+MFNwY6bK3HEXE3AQPvuOtp7FQQYX+2BgLQwMiyKThKg5V4KcmsDR3zvqQ 7 | Rdrd4lXm5KAt8kLSF+VFFO+Fm0eJG7fQgERsBFuyHg16511dh1JC2cAu6E2IaFw2 8 | nUWyYsvjKCl3hcPqvmVl8MIFexhPw7cyUlq68PyEgYpDXzfgE1DIiu1BGQ5z/UZ2 9 | XzBTQKg7/+iVfdMjftYbRqLk3MKwaM0yuohVBLkkBKuY8H+93G4qizYGAs+Ae5Hi 10 | EYPUkkmQMYfOXhSF7cV2aDPcCAY9oJWDaQNBk3rx4v8CAwEAAaMeMBwwGgYDVR0R 11 | BBMwEYIPd3d3LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQC5mqAoFR1t 12 | tYR558EYxn91VVmFFeUdXtAbkWQ6LLLQPTbWz8bQW5qoj9mYF7r2AAKnJvJoAtUX 13 | ZYfVlHhEenGG9x8U/he/4L8IubHySMrksmoGVC5vS/0ecSD0pjObcNa6ZZH+ELbf 14 | O1Fm1vP/QzOZeQoH2C4tdtDNXS9JV0F4ZGOHQALEBNkO5CfOVXd3YhmGGLFxkgjs 15 | I135CtslJTR3+GpPHg44/Lo7VvwuSp0gJIzgLayM8Hcb7fKpZ0D2FsRkc4dDIwuR 16 | wDYojnaUIAuni1Dd8oguYvm5+S56XOOO9BNDorxNzqqHuwEsqszG86VBEkMAB5v+ 17 | AQ86ecyUH90A 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /util/parse_templated_path.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | ) 7 | 8 | // ParseTemplatedPath parses a url-like path using an input template and outputs a map of matched values. 9 | // template should place the named params to be extracted in single braces, e.g. 10 | // ParseTemplatedPath("{my_param1}/literal/path/{my_param2}/parts", "foo/literal/path/bar/parts") 11 | // returns {"my_param1": "foo", "my_param2": "bar"} 12 | func ParseTemplatedPath(template string, path string) (map[string]string, error) { 13 | // escape any needed strings for regex 14 | template = regexp.QuoteMeta(template) 15 | // convert braces to capture groups 16 | template = strings.Replace(template, `\{`, `(?P<`, -1) 17 | template = "^" + strings.Replace(template, `\}`, `>[a-zA-z0-9_\-]+)`, -1) 18 | rex, err := regexp.Compile(template) 19 | if err != nil { 20 | return nil, err 21 | } 22 | match := rex.FindStringSubmatch(path) 23 | names := rex.SubexpNames() 24 | params := map[string]string{} 25 | for i, name := range names { 26 | if i != 0 && len(match) > i { 27 | params[name] = match[i] 28 | } 29 | } 30 | return params, nil 31 | } 32 | -------------------------------------------------------------------------------- /cicd/docs/docs_md.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Run from ./cicd/docs/../.. directory (root of repo) 4 | cd "$(dirname "$0")/../.." 5 | 6 | GO111MODULE=off go get github.com/robertkrimen/godocdown/godocdown 7 | GO_NON_TEST_NON_EXAMPLE_PACKAGES=$(go list ./... | grep -v test | grep -v examples) 8 | 9 | rm -rf docs/ 10 | mkdir -p docs/pkg 11 | 12 | DOC_INDEX=" 13 | 14 | # github.com/splunk/splunk-cloud-sdk-go 15 | 16 | ## Packages 17 | 18 | " 19 | 20 | for PACKAGE in $GO_NON_TEST_NON_EXAMPLE_PACKAGES 21 | do 22 | DOC_FILE=$(echo $PACKAGE | sed "s/[\.|\/|-]/_/g").md 23 | PKG_LOC=$(echo $PACKAGE | sed "s/github\.com\/splunk\/splunk-cloud-sdk-go/./g") 24 | echo "running $GOPATH/bin/godocdown $PKG_LOC > docs/pkg/$DOC_FILE ..." 25 | # escape . and / characters for replacing in the next step 26 | PACKAGE_ESC=$(echo $PACKAGE | sed 's|\.|\\.|g') 27 | $GOPATH/bin/godocdown $PKG_LOC | sed "s|import \"\.\"|import \"$PACKAGE_ESC\"|g" > docs/pkg/$DOC_FILE 28 | echo "Wrote docs for $PACKAGE to docs/pkg/$DOC_FILE" 29 | echo "" 30 | DOC_INDEX+="* [$PACKAGE](pkg/$DOC_FILE) 31 | " 32 | done 33 | 34 | echo "$DOC_INDEX" > docs/README.md 35 | echo "Wrote docs index to docs/README.md" -------------------------------------------------------------------------------- /cmd/scloud/cmd/login/login.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | impl "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/pkg/login" 6 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 7 | ) 8 | 9 | // Cmd -- used to connection to rootCmd 10 | func Cmd() *cobra.Command { 11 | return loginCmd 12 | } 13 | 14 | // loginCmd represents the login command 15 | var loginCmd = &cobra.Command{ 16 | Use: "login", 17 | Short: "Log in to Splunk Cloud Services", 18 | RunE: impl.Login, 19 | } 20 | 21 | func init() { 22 | 23 | loginCmd.Flags().StringP("uid", "u", "", "Your username") 24 | loginCmd.Flags().StringP("pwd", "p", "", "Your password") 25 | loginCmd.Flags().BoolP("verbose", "", false, "Whether to display your access token") 26 | 27 | // Auth flow flags 28 | loginCmd.Flags().BoolP("use-refresh-token", "", false, "Whether to use refresh token authentication flow") 29 | loginCmd.Flags().BoolP("use-pkce", "", false, "use PKCE authentication flow") 30 | loginCmd.Flags().BoolP("use-device", "", false, "use device authentication flow") 31 | 32 | loginCmd.SetUsageTemplate(usageUtil.UsageTemplate) 33 | loginCmd.SetHelpTemplate(usageUtil.HelpTemplate) 34 | } 35 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_create_group.json: -------------------------------------------------------------------------------- 1 | { 2 | "arguments": [ 3 | { 4 | "groupArg": "time", 5 | "position": 0, 6 | "type": "long" 7 | } 8 | ], 9 | "ast": { 10 | "edges": [ 11 | { 12 | "sourceNode": "9953fede-aa87-4a6e-823a-64176915723b", 13 | "sourcePort": "output", 14 | "targetNode": "b3c6a990-ee54-4a20-a900-67cca16c18be", 15 | "targetPort": "input" 16 | } 17 | ], 18 | "nodes": [ 19 | { 20 | "attributes": {}, 21 | "id": "9953fede-aa87-4a6e-823a-64176915723b", 22 | "op": "read-splunk-firehose", 23 | "resolvedId": "read-splunk-firehose" 24 | }, 25 | { 26 | "attributes": {}, 27 | "dataset": "dataset:main", 28 | "id": "b3c6a990-ee54-4a20-a900-67cca16c18be", 29 | "module": "module:index", 30 | "op": "write-index", 31 | "resolvedId": "write-index:collection>:expression:expression" 32 | } 33 | ], 34 | "rootNode": [ 35 | "b3c6a990-ee54-4a20-a900-67cca16c18be" 36 | ] 37 | }, 38 | "attributes": null, 39 | "categories": null, 40 | "mappings": null, 41 | "name": "test-fn", 42 | "outputType": "" 43 | } -------------------------------------------------------------------------------- /cicd/integration/run_scloud_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "===============================================" 4 | echo "Beginning scloud integration tests" 5 | echo "===============================================" 6 | echo "TEST_USERNAME=$TEST_USERNAME" 7 | echo "TEST_TENANT_SCOPED=$TEST_TENANT_SCOPED" 8 | echo "SPLUNK_CLOUD_HOST_TENANT_SCOPED=$SPLUNK_CLOUD_HOST_TENANT_SCOPED" 9 | echo "===============================================" 10 | 11 | COMMA_SEPARATED_FULLY_QUALIFIED_PACKAGES=$(go list ./... | grep -v test | awk -v ORS=, '{ print $1 }' | sed 's/,$//') 12 | 13 | if [[ "$allow_failures" == "1" ]]; then 14 | echo "Running integration tests but not gating on failures..." 15 | else 16 | echo "Running integration tests and gating on failures..." 17 | fi 18 | 19 | set +e 20 | gotestsum --format short-verbose \ 21 | -- github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/test \ 22 | -timeout 10m 23 | result=$? 24 | 25 | if [[ "$result" -gt "0" ]]; then 26 | echo "Tests FAILED" 27 | if [[ "$allow_failures" == "1" ]]; then 28 | echo "... but not gating, exiting with status 0" 29 | exit 0 30 | else 31 | echo "... gating on failure, exiting with status 1" 32 | exit 1 33 | fi 34 | fi -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/kvstore_test: -------------------------------------------------------------------------------- 1 | kvstore create-index --name myindex --fields "[{\"direction\":-1,\"field\":\"integ_testField1\"}]" --collection gomod1582754557.gointegdskvidx_1582754557 2 | kvstore delete-index --collection gomod1582754557.gointegdskvidx_1582754557 --index myindex 3 | kvstore list-indexes --collection gomod1582754557.gointegdskvidx_1582754557 4 | kvstore ping 5 | kvstore insert-record --collection gomod1582754557.gointegdskvidx_1582754557 --body "{\"capacity_gb\": 8}" 6 | kvstore list-records --collection gomod1582754557.gointegdskvidx_1582754557 7 | kvstore insert-records --collection gomod1582754557.gointegdskvidx_1582754557 --body "[{\"capacity_gb\": 8},{\"capacity_gb\": 7}]" 8 | kvstore put-record --collection gomod1582754557.gointegdskvidx_1582754557 --key "5e58525673875400011ffb13" --body "{\"capacity_gb\": 8}" 9 | kvstore query-records --collection gomod1582754557.gointegdskvidx_1582754557 10 | kvstore get-record-by-key --collection gomod1582754557.gointegdskvidx_1582754557 --key "5e58525673875400011ffb13" 11 | kvstore delete-record-by-key --collection gomod1582754557.gointegdskvidx_1582754557 --key "5e58525673875400011ffb13" 12 | kvstore delete-records --collection gomod1582754557.gointegdskvidx_1582754557 13 | 14 | 15 | -------------------------------------------------------------------------------- /services/search/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package search 20 | 21 | import ( 22 | "time" 23 | ) 24 | 25 | // Servicer represents the interface for implementing all endpoints for this service 26 | type Servicer interface { 27 | //interfaces that cannot be auto-generated from codegen 28 | // WaitForJob polls the job until it's completed or errors out 29 | WaitForJob(jobID string, pollInterval time.Duration) (interface{}, error) 30 | 31 | //interfaces that are auto-generated in interface_generated.go 32 | ServicerGenerated 33 | } 34 | -------------------------------------------------------------------------------- /cmd/scloud/test/cli_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "testing" 5 | 6 | test_engine "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/test/utils" 7 | ) 8 | 9 | func TestCli_action(t *testing.T) { 10 | test_engine.RunTest("testcases/action_test", t) 11 | } 12 | 13 | func TestCli_appreg(t *testing.T) { 14 | test_engine.RunTest("testcases/appreg_test", t) 15 | } 16 | 17 | func TestCli_catalog(t *testing.T) { 18 | test_engine.RunTest("testcases/catalog_test", t) 19 | } 20 | 21 | func TestCli_collect(t *testing.T) { 22 | test_engine.RunTest("testcases/collect_test", t) 23 | } 24 | 25 | func TestCli_forwarders(t *testing.T) { 26 | test_engine.RunTest("testcases/forwarders_test", t) 27 | } 28 | 29 | func TestCli_identity(t *testing.T) { 30 | test_engine.RunTest("testcases/identity_test", t) 31 | } 32 | 33 | func TestCli_ingest(t *testing.T) { 34 | test_engine.RunTest("testcases/ingest_test", t) 35 | } 36 | 37 | func TestCli_kvstore(t *testing.T) { 38 | test_engine.RunTest("testcases/kvstore_test", t) 39 | } 40 | 41 | func TestCli_provisioner(t *testing.T) { 42 | test_engine.RunTest("testcases/provisioner_test", t) 43 | } 44 | 45 | func TestCli_search(t *testing.T) { 46 | test_engine.RunTest("testcases/search_test", t) 47 | } 48 | 49 | func TestCli_streams(t *testing.T) { 50 | test_engine.RunTest("testcases/streams_test", t) 51 | } 52 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/ingest_test: -------------------------------------------------------------------------------- 1 | ingest post-events --host scloud_test_ingest_host --source scloud_test_ingest_source --format raw < test_ingest_event_raw.log 2 | ingest post-events --host scloud_test_ingest_host --source scloud_test_ingest_source --sourcetype scloud_test_ingest_sourcetype --id scloud_test_ingest_id --format json < test_ingest_event_json.log 3 | ingest post-events --host scloud_test_ingest_host --source scloud_test_ingest_source --sourcetype scloud_test_ingest_sourcetype --id scloud_test_ingest_id --attributes {"scloud_test_ingest_attribute":{"scloud_test_ingest_key":"scloud_test_ingest_value"}} --format event < test_ingest_event_json.log 4 | 5 | ingest post-metrics --host scloud_test_ingest_host_m --source scloud_test_ingest_source_m --sourcetype scloud_test_ingest_sourcetype_m --id scloud_test_ingest_id_m --nanos 1 --timestamp 1580891104000 --default-dimensions {"scloud_test_metric_dimension_default_key":"scloud_test_metric_dimension_default_value"} < test_ingest_metric_json.log 6 | ingest post-metrics --host scloud_test_ingest_host_m --source scloud_test_ingest_source_m --sourcetype scloud_test_ingest_sourcetype_m --id scloud_test_ingest_id_m --nanos 1 --timestamp 1580891104000 --default-type scloud_test_metric_type_default --default-unit scloud_test_metric_unit_default < test_ingest_metric_json.log 7 | 8 | ingest upload-files --file-name test_ingest_event_raw.log 9 | 10 | -------------------------------------------------------------------------------- /util/credential.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package util 18 | 19 | // Credential is a simple string whose value is redacted when converted to a 20 | // string via the Stringer interface in order to prevent accidental logging or 21 | // other unintentional disclosure - value is retrieved using ClearText() method 22 | type Credential struct { 23 | string 24 | } 25 | 26 | // NewCredential creates a Credential from a simple string 27 | func NewCredential(s string) *Credential { 28 | return &Credential{s} 29 | } 30 | 31 | // String returns a redacted string 32 | func (c *Credential) String() string { 33 | return "XXXXX" 34 | } 35 | 36 | // ClearText returns the actual cleartext string value 37 | func (c *Credential) ClearText() string { 38 | return c.string 39 | } 40 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/collect_test: -------------------------------------------------------------------------------- 1 | collect create-execution --job-id 8b631454-c042-451e-80d7-2bb30bbc3ba2 2 | collect create-job --connector-ID aws-cloudwatch-metrics --name collector12 --parameters "{\"namespaces\": \"AWSEC2\"}" --schedule "16 * * * *" --scale-policy "{\"Static\": {\"Workers\":2}}" 3 | collect delete-job --job-id 960173a2-3d21-4309-addb-0b2c2d43946e 4 | collect delete-jobs 5 | collect get-execution --job-id 962b9053-5479-41bc-a5f6-e51f1c441496 --execution-uid 9a712d93-49b7-4c6d-9f1d-17df2a6d9249 6 | collect get-job --job-id 960173a2-3d21-4309-addb-0b2c2d43946e 7 | collect list-jobs --connector-id my-connector:v1.0.0dsfsdf 8 | collect patch-execution --job-id 962b9053-5479-41bc-a5f6-e51f1c441496 --execution-uid 9a712d93-49b7-4c6d-9f1d-17df2a6d9249 --status canceled 9 | collect patch-job --job-id e414f500-e165-44e4-a88e-d2dbdec569ca --name collector12 --parameters "{\"namespaces\": \"AWSEC2\"}" --schedule "17 * * * *" --scale-policy "{\"Static\": {\"Workers\":2}}" --scheduled false 10 | collect patch-jobs --job-ids e414f500-e165-44e4-a88e-d2dbdec569ca --scale-policy "{\"Static\": {\"Workers\":2}}" 11 | collect patch-jobs --connector-id my-connector:v2.0.0 12 | collect patch-jobs --connector-id my-connector:v2.0.0 --scale-policy "{\"Static\": {\"Workers\":2}}" 13 | collect patch-jobs --job-ids "962b9053-5479-41bc-a5f6-e51f1c441496,004832bf-bbb8-4707-a9ff-5c2cfe4bf633" --event-extra-fields "[{\"name\": \"test\",\"value\":\"value1\"}]" 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /cmd/scloud/util/templates.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | const UsageTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} 4 | {{end}}{{if or .Runnable .HasSubCommands}}{{end}} 5 | Usage:{{if .Runnable}} 6 | {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} 7 | {{.CommandPath}} [command]{{end}} 8 | 9 | Use "{{.CommandPath}} --help" for more information about a command. 10 | ` 11 | 12 | const HelpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} 13 | {{end}}{{if or .Runnable .HasSubCommands}}{{end}} 14 | Usage:{{if .Runnable}} 15 | {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} 16 | {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} 17 | 18 | Aliases: 19 | {{.NameAndAliases}}{{end}}{{if .HasExample}} 20 | 21 | Examples: 22 | {{.Example}}{{end}}{{if .HasAvailableSubCommands}} 23 | 24 | Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} 25 | {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} 26 | 27 | Flags: 28 | {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} 29 | 30 | Global Flags: 31 | {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} 32 | 33 | Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} 34 | {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} 35 | 36 | Use "{{.CommandPath}} --help" for more information about a command.{{end}} 37 | ` 38 | -------------------------------------------------------------------------------- /services/appregistry/param_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2022 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | * 16 | * App Registry 17 | * 18 | * With the App Registry service in Splunk Cloud Services, you can create, update, and manage your apps. 19 | * 20 | * API version: v1beta2.0 (recommended default) 21 | * Generated by: OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. 22 | */ 23 | 24 | package appregistry 25 | 26 | // ListSubscriptionsQueryParams represents valid query parameters for the ListSubscriptions operation 27 | // For convenience ListSubscriptionsQueryParams can be formed in a single statement, for example: 28 | // `v := ListSubscriptionsQueryParams{}.SetKind(...)` 29 | type ListSubscriptionsQueryParams struct { 30 | // Kind : The kind of application. 31 | Kind AppResourceKind `key:"kind"` 32 | } 33 | 34 | func (q ListSubscriptionsQueryParams) SetKind(v AppResourceKind) ListSubscriptionsQueryParams { 35 | q.Kind = v 36 | return q 37 | } 38 | -------------------------------------------------------------------------------- /cmd/scloud/test/utils/env-variables.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package test_engine 18 | 19 | import "os" 20 | 21 | // TestSplunkCloudHost - the url for the test api to be used 22 | var TestSplunkCloudHost = os.Getenv("SPLUNK_CLOUD_HOST_TENANT_SCOPED") 23 | 24 | //Invalid Host Url 25 | var InvalidHostUrl = "https://InvalidHostUrl:443" 26 | 27 | // TestTenant - the tenant to be used for the API 28 | var TestTenant = os.Getenv("TEST_TENANT_SCOPED") 29 | 30 | //Username to be used in scloud login flow 31 | var Username = os.Getenv("TEST_USERNAME") 32 | 33 | var Password = os.Getenv("TEST_PASSWORD") 34 | 35 | //Auth url to provide token for request validation 36 | var IdpHost = os.Getenv("IDP_HOST") 37 | 38 | //Invalid Auth Url 39 | var InvalidAuthUrl = "https://InvalidAuthUrl:443" 40 | 41 | //Valid test env1 42 | var Env1 = os.Getenv("TEST_ENVIRONMENT_1") 43 | 44 | //Valid test env2 45 | var Env2 = os.Getenv("TEST_ENVIRONMENT_2") 46 | -------------------------------------------------------------------------------- /cicd/whitesource/whitesource-fs-agent.config: -------------------------------------------------------------------------------- 1 | #################################################################### 2 | # WhiteSource FS-Agent configuration file 3 | #################################################################### 4 | ########################################## 5 | # GENERAL SCAN MODE: Files and Package Managers 6 | ########################################## 7 | checkPolicies=false 8 | forceCheckAllDependencies=false 9 | forceUpdate=false 10 | forceUpdate.failBuildOnPolicyViolation=false 11 | offline=false 12 | 13 | wss.url=https://saas.whitesourcesoftware.com/agent 14 | 15 | ################################## 16 | # Organization tokens: 17 | ################################## 18 | projectName=Splunk-Cloud-SDK-Go 19 | 20 | ######################################################################################### 21 | # Includes/Excludes Glob patterns - PLEASE USE ONLY ONE EXCLUDE LINE AND ONE INCLUDE LINE 22 | ######################################################################################### 23 | includes=**/*.go 24 | 25 | case.sensitive.glob=false 26 | followSymbolicLinks=true 27 | 28 | ################################## 29 | # Go Specific Configurations 30 | ################################## 31 | go.resolveDependencies=true 32 | go.collectDependenciesAtRuntime=true 33 | # Which Go dependency manager to use when scanning Go project. 34 | # Valid values are dep, godep or vndr. 35 | # If empty the FSA will try to resolve the dependencies using dep, if its 36 | # missing the FSA will use godep, and finally will use vndr 37 | # go.dependencyManager= 38 | -------------------------------------------------------------------------------- /cicd/integration/runexamples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "===============================================" 4 | echo "Running examples" 5 | echo "===============================================" 6 | echo "SPLUNK_CLOUD_HOST_TENANT_SCOPED=$SPLUNK_CLOUD_HOST_TENANT_SCOPED" 7 | echo "TEST_TENANT_SCOPED=$TEST_TENANT_SCOPED" 8 | echo "===============================================" 9 | 10 | COMMA_SEPARATED_FULLY_QUALIFIED_PACKAGES=$(go list ./... | grep -v test | awk -v ORS=, '{ print $1 }' | sed 's/,$//') 11 | 12 | if [[ "$allow_failures" == "1" ]]; then 13 | echo "Running examples but not gating on failures..." 14 | echo "" 15 | echo "Running ingestSearch ..." 16 | go run -v ./examples/ingestSearch/ingestSearch.go || exit 0 17 | echo "Running logging ..." 18 | go run -v ./examples/logging/logging.go -logfile example.log || exit 0 19 | echo "example.log output:" 20 | (ls example.log && cat example.log| sed -e "s/Authorization: Bearer .*/Authorization: Bearer /g") || exit 0 21 | else 22 | echo "Running examples and gating on failures..." 23 | set +e 24 | echo "" 25 | echo "Running ingestSearch ..." 26 | go run -v ./examples/ingestSearch/ingestSearch.go || exit 1 27 | echo "Running logging ..." 28 | go run -v ./examples/logging/logging.go -logfile example.log || exit 1 29 | echo "example.log output:" 30 | (ls example.log && cat example.log| sed -e "s/Authorization: Bearer .*/Authorization: Bearer /g") || exit 1 31 | echo "Running mock ..." 32 | go run -v ./examples/mock/mock.go || exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/forwarders_test.expected: -------------------------------------------------------------------------------- 1 | #testcase: forwarders add-certificate --input-datafile testcases/test_forwarders_pem.pem 2 | REQUEST URL:forwarders/v2beta1/certificates 3 | REQUEST BODY:{{"pem":"-----BEGIN CERTIFICATE-----\nMIIC1TCCAb2gAwIBAgIJAIOAwz2qyz1FMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV\nBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0yMTA4MjcxOTAwNTVaFw0yNjA4MjYxOTAw\nNTVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBANHY9Uc+AJL17z6GkJ9VoiPU0TDF3+rVjp2CLxcc2Upt\nBgX//F+MFNwY6bK3HEXE3AQPvuOtp7FQQYX+2BgLQwMiyKThKg5V4KcmsDR3zvqQ\nRdrd4lXm5KAt8kLSF+VFFO+Fm0eJG7fQgERsBFuyHg16511dh1JC2cAu6E2IaFw2\nnUWyYsvjKCl3hcPqvmVl8MIFexhPw7cyUlq68PyEgYpDXzfgE1DIiu1BGQ5z/UZ2\nXzBTQKg7/+iVfdMjftYbRqLk3MKwaM0yuohVBLkkBKuY8H+93G4qizYGAs+Ae5Hi\nEYPUkkmQMYfOXhSF7cV2aDPcCAY9oJWDaQNBk3rx4v8CAwEAAaMeMBwwGgYDVR0R\nBBMwEYIPd3d3LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQC5mqAoFR1t\ntYR558EYxn91VVmFFeUdXtAbkWQ6LLLQPTbWz8bQW5qoj9mYF7r2AAKnJvJoAtUX\nZYfVlHhEenGG9x8U/he/4L8IubHySMrksmoGVC5vS/0ecSD0pjObcNa6ZZH+ELbf\nO1Fm1vP/QzOZeQoH2C4tdtDNXS9JV0F4ZGOHQALEBNkO5CfOVXd3YhmGGLFxkgjs\nI135CtslJTR3+GpPHg44/Lo7VvwuSp0gJIzgLayM8Hcb7fKpZ0D2FsRkc4dDIwuR\nwDYojnaUIAuni1Dd8oguYvm5+S56XOOO9BNDorxNzqqHuwEsqszG86VBEkMAB5v+\nAQ86ecyUH90A\n-----END CERTIFICATE-----\n"}} 4 | 5 | #testcase: forwarders list-certificates 6 | REQUEST URL:forwarders/v2beta1/certificates 7 | REQUEST BODY: 8 | 9 | #testcase: forwarders delete-certificate --slot 1 10 | REQUEST URL:forwarders/v2beta1/certificates/1 11 | REQUEST BODY: 12 | 13 | #testcase: forwarders delete-certificates 14 | REQUEST URL:forwarders/v2beta1/certificates 15 | REQUEST BODY: 16 | 17 | -------------------------------------------------------------------------------- /services/action/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package action 20 | 21 | // Servicer represents the interface for implementing all endpoints for this service 22 | type Servicer interface { 23 | //interfaces that cannot be auto-generated from codegen 24 | /* 25 | TriggerActionWithStatus - Trigger an action and return a TriggerResponse with StatusID 26 | 27 | Parameters: 28 | actionName: The name of the action, as one or more identifier strings separated by periods. Each identifier string consists of lowercase letters, digits, and underscores, and cannot start with a digit. 29 | triggerEvent: The action payload, which must include values for any templated fields. 30 | */ 31 | TriggerActionWithStatus(actionName string, triggerEvent TriggerEvent) (*TriggerResponse, error) 32 | 33 | //interfaces that are auto-generated in interface_generated.go 34 | ServicerGenerated 35 | } 36 | -------------------------------------------------------------------------------- /services/streams/model_sdk.go: -------------------------------------------------------------------------------- 1 | package streams 2 | 3 | // PipelineStatusQueryParams contains the query parameters that can be provided by the user to fetch specific pipeline job statuses 4 | type PipelineStatusQueryParams struct { 5 | Offset *int32 `json:"offset,omitempty"` 6 | PageSize *int32 `json:"pageSize,omitempty"` 7 | SortField *string `json:"sortField,omitempty"` 8 | SortDir *string `json:"sortDir,omitempty"` 9 | Activated *bool `json:"activated,omitempty"` 10 | CreateUserID *string `json:"createUserId,omitempty"` 11 | Name *string `json:"name,omitempty"` 12 | } 13 | 14 | // AdditionalProperties contain the properties in an activate/deactivate response 15 | type AdditionalProperties map[string][]string 16 | 17 | // PipelineQueryParams contains the query parameters that can be provided by the user to fetch specific pipelines 18 | type PipelineQueryParams struct { 19 | Offset *int32 `json:"offset,omitempty"` 20 | PageSize *int32 `json:"pageSize,omitempty"` 21 | SortField *string `json:"sortField,omitempty"` 22 | SortDir *string `json:"sortDir,omitempty"` 23 | Activated *bool `json:"activated,omitempty"` 24 | CreateUserID *string `json:"createUserId,omitempty"` 25 | Name *string `json:"name,omitempty"` 26 | IncludeData *bool `json:"includeData,omitempty"` 27 | } 28 | 29 | // PartialTemplateRequest contains the template request data for partial update operation 30 | type PartialTemplateRequest struct { 31 | Data *Pipeline `json:"data,omitempty"` 32 | Description *string `json:"description,omitempty"` 33 | Name *string `json:"name,omitempty"` 34 | } 35 | -------------------------------------------------------------------------------- /cicd/scripts/token.sh: -------------------------------------------------------------------------------- 1 | # Cross-platform sed -i: https://stackoverflow.com/a/38595160 2 | sedi () { 3 | sed --version >/dev/null 2>&1 && sed -i -- "$@" || sed -i "" "$@" 4 | } 5 | 6 | # If any of the required env variables are unset, fail fast 7 | 8 | if [[ -z "$BASE64_ENCODED_BASIC_AUTH_TENANT_SCOPED" ]]; then 9 | echo "BASE64_ENCODED_BASIC_AUTH_TENANT_SCOPED was not set" 10 | exit 1 11 | fi 12 | 13 | if [[ -z "$IDP_HOST_TENANT_SCOPED" ]]; then 14 | echo "IDP_HOST_TENANT_SCOPED was not set" 15 | exit 1 16 | fi 17 | 18 | # Optional env variables 19 | IDP_TOKEN_BODY="grant_type=client_credentials" 20 | 21 | echo "Fetching access token..." 22 | CURL_RESPONSE=$(curl --request POST --url $IDP_HOST_TENANT_SCOPED/token \ 23 | --header 'accept: application/json' \ 24 | --header "Authorization: Basic $BASE64_ENCODED_BASIC_AUTH_TENANT_SCOPED" \ 25 | --header 'content-type: application/x-www-form-urlencoded' --data "$IDP_TOKEN_BODY") 26 | 27 | ACCESS_TOKEN=$(printf "$CURL_RESPONSE" | jq -r ".access_token") 28 | 29 | if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then 30 | echo "Unable to set ACCESS_TOKEN, response from idp:\n\n$CURL_RESPONSE" 31 | exit 1 32 | fi 33 | 34 | touch .env 35 | 36 | if grep -q '^BEARER_TOKEN=' .env; then 37 | if sedi "s/BEARER_TOKEN=.*/BEARER_TOKEN=${ACCESS_TOKEN}/" .env; then 38 | echo "access_token updated in .env" 39 | fi 40 | else 41 | if echo "BEARER_TOKEN=${ACCESS_TOKEN}" | tee -a .env >/dev/null; then 42 | echo "access_token written to .env" 43 | fi 44 | fi 45 | 46 | grep -q '^BEARER_TOKEN=' .env 47 | 48 | if [ $? -ne 0 ] 49 | then 50 | echo "failed writing access_token to .env" 51 | exit 1 52 | fi 53 | -------------------------------------------------------------------------------- /services/ingest/param_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2022 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | * 16 | * Ingest API 17 | * 18 | * Use the Ingest service in Splunk Cloud Services to send event and metrics data, or upload a static file, to Splunk Cloud Services. 19 | * 20 | * API version: v1beta2.32 (recommended default) 21 | * Generated by: OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. 22 | */ 23 | 24 | package ingest 25 | 26 | // ListCollectorTokensQueryParams represents valid query parameters for the ListCollectorTokens operation 27 | // For convenience ListCollectorTokensQueryParams can be formed in a single statement, for example: 28 | // `v := ListCollectorTokensQueryParams{}.SetLimit(...).SetOffset(...)` 29 | type ListCollectorTokensQueryParams struct { 30 | Limit *int64 `key:"limit"` 31 | Offset *int64 `key:"offset"` 32 | } 33 | 34 | func (q ListCollectorTokensQueryParams) SetLimit(v int64) ListCollectorTokensQueryParams { 35 | q.Limit = &v 36 | return q 37 | } 38 | 39 | func (q ListCollectorTokensQueryParams) SetOffset(v int64) ListCollectorTokensQueryParams { 40 | q.Offset = &v 41 | return q 42 | } 43 | -------------------------------------------------------------------------------- /services/forwarders/model_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2022 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | * 16 | * Splunk Forwarder Service 17 | * 18 | * Send data from a Splunk forwarder to the Splunk Forwarder service in Splunk Cloud Services. 19 | * 20 | * API version: v2beta1.4 (recommended default) 21 | * Generated by: OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. 22 | */ 23 | 24 | package forwarders 25 | 26 | type Certificate struct { 27 | Pem string `json:"pem"` 28 | } 29 | 30 | type CertificateInfo struct { 31 | Content *string `json:"content,omitempty"` 32 | Hash *string `json:"hash,omitempty"` 33 | Issuer *string `json:"issuer,omitempty"` 34 | LastUpdate *string `json:"lastUpdate,omitempty"` 35 | NotAfter *string `json:"notAfter,omitempty"` 36 | NotBefore *string `json:"notBefore,omitempty"` 37 | Slot *int64 `json:"slot,omitempty"` 38 | Subject *string `json:"subject,omitempty"` 39 | } 40 | 41 | type Error struct { 42 | Code *string `json:"code,omitempty"` 43 | Details map[string]interface{} `json:"details,omitempty"` 44 | Message *string `json:"message,omitempty"` 45 | } 46 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | 4 | ## Issues and bug reports 5 | 6 | If you see unexpected behavior with this project, please [create an issue on GitHub](/issues) with the following information: 7 | 8 | - A title and a clear description of the issue. 9 | - The project version (for example "0.1.4"). 10 | - The framework version (for example "Go 1.11"). 11 | 12 | If possible, include the following to help us reproduce the issue: 13 | - A code sample that demonstrates the issue. 14 | - Any unit test cases that show how the expected behavior is not occurring. 15 | - An executable test case. 16 | 17 | If you have a question about Splunk, see [Splunk Answers](https://answers.splunk.com). 18 | 19 | ## Development 20 | 21 | Configure your development environment as described in the project [README](/blob/master/README.md). 22 | 23 | ## Submit a pull request 24 | 25 | 1. Fill out the [Splunk Contribution Agreement](https://www.splunk.com/goto/contributions). 26 | 2. Create a new branch. For example: 27 | 28 | ``` 29 | git checkout -b my-branch develop 30 | ``` 31 | 32 | 3. Make code changes in your branch with tests. 33 | 4. Commit your changes. 34 | 5. Push your branch to GitHub. 35 | 36 | ``` 37 | git push origin my-branch 38 | ``` 39 | 40 | 6. In GitHub, create a pull request that targets the **develop** branch. CI tests are run automatically. 41 | 7. After the pull request is merged, delete your branch. 42 | 8. Pull changes from the **develop** branch. 43 | 44 | ``` 45 | git checkout develop 46 | git pull develop 47 | ``` 48 | 49 | ## Contact us 50 | 51 | If you have questions, reach out to us on [Slack](https://splunkdevplatform.slack.com) in the **#sdc** channel or email us at _sdcbeta@splunk.com_. -------------------------------------------------------------------------------- /util/logs.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | 23 | "github.com/golang/glog" 24 | ) 25 | 26 | // Prints an info message. 27 | func Info(msg string, args ...interface{}) { 28 | msg = fmt.Sprintf(msg, args...) 29 | glog.Infof("info: %s\n", msg) 30 | } 31 | 32 | // Prints a fatal error message and exits. 33 | func Fatal(msg string, args ...interface{}) { 34 | msg = fmt.Sprintf(msg, args...) 35 | glog.Exitf("fatal error: %s\n", msg) 36 | } 37 | 38 | // Prints a warning message. 39 | func Warning(msg string, args ...interface{}) { 40 | msg = fmt.Sprintf(msg, args...) 41 | glog.Warningf("warning: %s\n", msg) 42 | } 43 | 44 | // Prints an error message. 45 | func Error(msg string, args ...interface{}) { 46 | msg = fmt.Sprintf(msg, args...) 47 | glog.Errorf("error: %s\n", msg) 48 | } 49 | 50 | // Checks if log directory exists. It creates the log directory, if it doesn't exist. 51 | func CreateLogDirectory(logPath string) { 52 | if _, err := os.Stat(logPath); os.IsNotExist(err) { 53 | err = os.Mkdir(logPath, 0700) 54 | if err != nil { 55 | fmt.Printf("error creating log folder: %s", err.Error()) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /cicd/integration/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "===============================================" 4 | echo "Beginning integration tests" 5 | echo "===============================================" 6 | echo "TEST_USERNAME=$TEST_USERNAME" 7 | echo "SPLUNK_CLOUD_HOST_TENANT_SCOPED=$SPLUNK_CLOUD_HOST_TENANT_SCOPED" 8 | echo "TEST_TENANT_SCOPED=$TEST_TENANT_SCOPED" 9 | echo "===============================================" 10 | 11 | COMMA_SEPARATED_FULLY_QUALIFIED_PACKAGES=$(go list ./... | grep -v test | awk -v ORS=, '{ print $1 }' | sed 's/,$//') 12 | 13 | PACKAGE_COVERAGE_PREFIX=./cicd/integration/ 14 | FULL_INTEGRATION_TEST_CODECOV_FILE_NAME=integration_test_codecov.out 15 | FULL_INTEGRATION_TEST_CODECOV_PATH=$PACKAGE_COVERAGE_PREFIX$FULL_INTEGRATION_TEST_CODECOV_FILE_NAME 16 | 17 | # Required to run just the service tests 18 | if [[ "$allow_failures" == "1" ]]; then 19 | echo "Running integration tests but not gating on failures..." 20 | else 21 | echo "Running integration tests and gating on failures..." 22 | fi 23 | 24 | set +e 25 | gotestsum --format short-verbose \ 26 | -- -coverpkg $COMMA_SEPARATED_FULLY_QUALIFIED_PACKAGES \ 27 | -covermode=count \ 28 | -coverprofile=$FULL_INTEGRATION_TEST_CODECOV_PATH \ 29 | -timeout 20m \ 30 | ./test/integration/... 31 | result=$? 32 | 33 | if [[ -z "${CI_PROJECT_DIR}" ]] ; then 34 | CI_PROJECT_DIR="$(pwd)/cicd/integration" 35 | fi 36 | 37 | mkdir -p $CI_PROJECT_DIR/coverage-integration 38 | mv $FULL_INTEGRATION_TEST_CODECOV_PATH $CI_PROJECT_DIR/coverage-integration/coverage.out 39 | 40 | if [[ "$result" -gt "0" ]]; then 41 | echo "Tests FAILED" 42 | if [[ "$allow_failures" == "1" ]]; then 43 | echo "... but not gating, exiting with status 0" 44 | exit 0 45 | else 46 | echo "... gating on failure, exiting with status 1" 47 | exit 1 48 | fi 49 | fi 50 | -------------------------------------------------------------------------------- /util/ticker.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "time" 21 | ) 22 | 23 | // Ticker is a wrapper of time.Ticker with additional functionality 24 | type Ticker struct { 25 | duration time.Duration 26 | ticker *time.Ticker 27 | running bool 28 | } 29 | 30 | // Reset resets ticker 31 | func (t *Ticker) Reset() { 32 | t.ticker.Stop() 33 | t.ticker = time.NewTicker(t.duration) 34 | } 35 | 36 | // Stop stops ticker and set property running to false 37 | func (t *Ticker) Stop() { 38 | t.ticker.Stop() 39 | t.running = false 40 | } 41 | 42 | // Start starts a new ticker and set property running to true 43 | func (t *Ticker) Start() { 44 | t.Reset() 45 | t.running = true 46 | } 47 | 48 | // IsRunning returns bool indicating whether or not ticker is running 49 | func (t *Ticker) IsRunning() bool { 50 | return t.running == true 51 | } 52 | 53 | // GetChan returns the channel from ticker 54 | func (t *Ticker) GetChan() <-chan time.Time { 55 | return t.ticker.C 56 | } 57 | 58 | // NewTicker spits out a pointer to Ticker model. It sets ticker to stop state by default 59 | func NewTicker(duration time.Duration) *Ticker { 60 | newTicker := time.NewTicker(duration) 61 | newTicker.Stop() 62 | return &Ticker{duration: duration, ticker: newTicker, running: false} 63 | } 64 | -------------------------------------------------------------------------------- /cmd/scloud/auth/statik/statik.go: -------------------------------------------------------------------------------- 1 | // Code generated by statik. DO NOT EDIT. 2 | 3 | // Package statik contains static assets. 4 | package statik 5 | 6 | import ( 7 | "github.com/rakyll/statik/fs" 8 | ) 9 | 10 | func init() { 11 | data := "PK\x03\x04\x14\x00\x08\x00\x08\x00\x0b\xac\xa6R\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00 \x00default.yamlUT\x05\x00\x01f`\x94`\xb4\x94Oo\xdb<\x0c\xc6\xef\xfa\x14BzN\x9a\xa4m\xea\xfa\xf8\xe2\xc5\x06\x0cm\xb7\x1e\xb6k SL\xc2F\x96\x14S\xee\xd2~\xfa\xc1v\xdc\xfcA\x0d\xb9Xv\xb3\xec\x87\xe4\xf33I]H\x8d\xde\xb8\xd7\x1cm\x90h_\xa8p\xb6zfqxH\x85\x94\xde\xa8\xd7e\xe1J\xab\xab\x93\x94\xca\xd3\x90\xb1x!\xc0\xe6\x85\x94+\xc7!\xad>\x8c\xf6\xe2\x11\x83\x1f\xb17\xa5]\x8f\xc0\xe5\xbbP\xdf\x15\xea#\xa1\xbep\x0b2\x98J\x06\xe3J=\xdc\xab\x85\xa8\xbf\xf6q\xf7YKq\x1fUq\x0ejIv\xd9\xa7~\xa3\xfc\xbc\x8f\xee\xb8\xd3\xff\xb2\x93\xb6?e\xc8\xc0}\x8c\x01G\x13\x03\x1f\xc0\xf6\xcd\xfbn<\x9e\x7f\x9fX\x1cM]\xcfRG\xe3\x13\xadv\x9c^\x88\x0b\xa9\xca\xb0B\x1b\x08T g\xdb\x00\x16\xedCU\xb1 nj\xaf\xc9\xeaT\xfa5`}dp\x1eS\xe9/ 29 | func getEndpointWithTenant(endpointName string) string { 30 | return fmt.Sprintf("/%v/%v", TestTenant, endpointName) 31 | } 32 | 33 | func deviceHandler(w http.ResponseWriter, r *http.Request) { 34 | w.Header().Set("Content-Type", "application/json") 35 | var response string 36 | 37 | if DEVICE_HANDLER_AUTHORIZED { 38 | w.WriteHeader(http.StatusOK) 39 | response = fmt.Sprintf("{\"device_code\":\"%v\",\"expires_in\":600,\"interval\":5,\"user_code\":\"%v\",\"verification_uri\":\"%v\"}", TEST_DEVICE_CODE, TEST_USER_CODE, TEST_VERIFICATION_URL) 40 | } else { 41 | w.WriteHeader(http.StatusUnauthorized) 42 | response = "Unauthorized" 43 | } 44 | 45 | w.Write([]byte(response)) 46 | } 47 | 48 | func tokenHandler(w http.ResponseWriter, r *http.Request) { 49 | w.Header().Set("Content-Type", "application/json") 50 | var response string 51 | 52 | if TOKEN_HANDLER_AUTHORIZED { 53 | w.WriteHeader(http.StatusOK) 54 | response = fmt.Sprintf("{\"device\": \"device\",\"scope\": \"offline_access email profile\",\"tenant\": \"%v\",\"user_code\": \"%v\"}", TestTenant, TEST_USER_CODE) 55 | } else { 56 | w.WriteHeader(http.StatusUnauthorized) 57 | response = "Unauthorized" 58 | } 59 | w.Write([]byte(response)) 60 | } 61 | -------------------------------------------------------------------------------- /cicd/unit_tests/run_unit_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "===============================================" 4 | echo "Beginning unit tests" 5 | echo "===============================================" 6 | 7 | GO_NON_TEST_PACKAGES=$(go list ./... | grep -v test) 8 | 9 | PACKAGE_COVERAGE_PREFIX=./cicd/unit_tests/ 10 | PACKAGE_COVERAGE_SUFFIX=_unit_test_code_cov.out 11 | FULL_UNIT_TEST_CODECOV_FILE_NAME=unit_test_codecov.out 12 | FULL_UNIT_TEST_CODECOV_PATH=$PACKAGE_COVERAGE_PREFIX$FULL_UNIT_TEST_CODECOV_FILE_NAME 13 | 14 | echo "------------------------------------------------------------------------------" 15 | echo "Unit tests will be output to $FULL_UNIT_TEST_CODECOV_PATH" 16 | echo "------------------------------------------------------------------------------" 17 | 18 | for PACKAGE in $GO_NON_TEST_PACKAGES 19 | do 20 | echo "-------------------------------------------------------------------" 21 | echo "Beginning unit tests for $PACKAGE" 22 | echo "-------------------------------------------------------------------" 23 | SANITIZED_PACKAGE_NAME=$(echo $PACKAGE | sed "s/[\.|\/|-]/_/g") 24 | COVERAGE_PACKAGE_OUTPUT_FILE=$PACKAGE_COVERAGE_PREFIX$SANITIZED_PACKAGE_NAME$PACKAGE_COVERAGE_SUFFIX 25 | 26 | # echo $SANITIZED_PACKAGE_NAME 27 | # echo $COVERAGE_PACKAGE_OUTPUT_FILE 28 | 29 | gotestsum --format short-verbose \ 30 | -- -covermode=count \ 31 | -coverprofile=$COVERAGE_PACKAGE_OUTPUT_FILE $PACKAGE 32 | 33 | RESULT=$? 34 | if [ $RESULT -ne 0 ] 35 | then 36 | echo "There was an error testing the $PACKAGE package's unit tests." 37 | exit 1 38 | fi 39 | 40 | if [ -f $COVERAGE_PACKAGE_OUTPUT_FILE ]; then 41 | cat $COVERAGE_PACKAGE_OUTPUT_FILE >> $FULL_UNIT_TEST_CODECOV_PATH 42 | else 43 | echo "No unit test results were found for $PACKAGE" 44 | fi 45 | done 46 | 47 | if [[ -z "${CI_PROJECT_DIR}" ]] ; then 48 | CI_PROJECT_DIR="$(pwd)/cicd/unit_tests" 49 | fi 50 | 51 | mkdir -p $CI_PROJECT_DIR/coverage-unit 52 | mv $FULL_UNIT_TEST_CODECOV_PATH $CI_PROJECT_DIR/coverage-unit/coverage.out -------------------------------------------------------------------------------- /cmd/scloud/pkg/ingest/ingest_non_generated_unit_test.go: -------------------------------------------------------------------------------- 1 | package ingest 2 | 3 | import ( 4 | "bufio" 5 | "strings" 6 | "testing" 7 | 8 | model "github.com/splunk/splunk-cloud-sdk-go/services/ingest" 9 | "github.com/stretchr/testify/assert" 10 | 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestReadBatch(t *testing.T) { 15 | s := "First event\n" + 16 | "Second event\n" + 17 | "Third event\n" 18 | reader := strings.NewReader(s) 19 | buf := bufio.NewReader(reader) 20 | 21 | output, err := readBatch(buf) 22 | require.Nil(t, err) 23 | require.NotNil(t, output) 24 | 25 | assert.Equal(t, 3, len(output)) 26 | } 27 | 28 | func TestReadBatchEmptyFile(t *testing.T) { 29 | s := "" 30 | reader := strings.NewReader(s) 31 | buf := bufio.NewReader(reader) 32 | 33 | output, err := readBatch(buf) 34 | require.NotNil(t, err) 35 | assert.EqualError(t, err, "EOF") 36 | require.Nil(t, output) 37 | } 38 | 39 | func TestPostBatchRaw(t *testing.T) { 40 | batch := []string{"first event", "second event"} 41 | 42 | host := "hoststr" 43 | source := "sourcestr" 44 | sourcetype := "sourcetypestr" 45 | 46 | args := model.Event{ 47 | Host: &host, 48 | Source: &source, 49 | Sourcetype: &sourcetype, 50 | } 51 | 52 | events, err := postBatchRaw(batch, args) 53 | require.Nil(t, err) 54 | 55 | assert.Equal(t, 2, len(events)) 56 | assert.Equal(t, host, *events[0].Host) 57 | assert.Equal(t, source, *events[0].Source) 58 | assert.Equal(t, sourcetype, *events[0].Sourcetype) 59 | } 60 | 61 | func TestPostBatchJSON(t *testing.T) { 62 | batch := []string{"[\"first event\"]", "[\"second event\"]"} 63 | 64 | host := "hoststr" 65 | source := "sourcestr" 66 | sourcetype := "sourcetypestr" 67 | 68 | args := model.Event{ 69 | Host: &host, 70 | Source: &source, 71 | Sourcetype: &sourcetype, 72 | } 73 | 74 | events, err := postBatchEventJSON(batch, args) 75 | require.Nil(t, err) 76 | 77 | assert.Equal(t, 2, len(events)) 78 | assert.Equal(t, host, *events[0].Host) 79 | assert.Equal(t, source, *events[0].Source) 80 | assert.Equal(t, sourcetype, *events[0].Sourcetype) 81 | 82 | } 83 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/identity_test: -------------------------------------------------------------------------------- 1 | identity create-group --name scloud_test_identity_group 2 | identity get-group --group scloud_test_identity_group 3 | 4 | identity add-member --name test1@splunk.com 5 | 6 | identity create-role --name scloud_test_identity_role 7 | 8 | identity list-role-permissions --role scloud_test_identity_role 9 | identity list-group-members --group scloud_test_identity_group 10 | identity list-member-groups --member test1@splunk.com 11 | identity list-member-permissions --member test1@splunk.com 12 | identity list-member-roles --member test1@splunk.com 13 | identity list-role-permissions --role scloud_test_identity_role 14 | identity list-group-roles --group scloud_test_identity_group 15 | 16 | identity add-group-member --group scloud_test_identity_group --name test1@splunk.com 17 | identity add-group-role --group scloud_test_identity_group --name scloud_test_identity_role 18 | identity add-role-permission --role scloud_test_identity_role --body gtestsdks:*:identity.groups.read 19 | 20 | identity get-role --role scloud_test_identity_role 21 | identity get-principal --principal srv-ssc-mt32intg@splunkcorp.com 22 | 23 | identity get-role-permission --role scloud_test_identity_role --permission gtestsdks:*:identity.groups.read 24 | identity get-group-role --group scloud_test_identity_group --role scloud_test_identity_role 25 | 26 | identity get-group-member --group scloud_test_identity_group --member test1@splunk.com 27 | identity get-member --member test1@splunk.com 28 | 29 | identity list-groups 30 | identity list-principals 31 | identity list-roles 32 | identity list-members 33 | 34 | identity validate-token --include tenant,principal 35 | 36 | identity remove-role-permission --role scloud_test_identity_role --permission gtestsdks:*:identity.groups.read 37 | 38 | identity remove-group-member --group scloud_test_identity_group --member test1@splunk.com 39 | identity remove-group-role --group scloud_test_identity_group --role scloud_test_identity_role 40 | identity remove-member --member test1@splunk.com 41 | 42 | identity delete-role --role scloud_test_identity_role 43 | identity delete-group --group scloud_test_identity_group 44 | 45 | -------------------------------------------------------------------------------- /cmd/scloud/test/record_result_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | test_engine "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/test/utils" 8 | ) 9 | 10 | // Tests in this file are recording test results. They should only be executed when updating test results 11 | 12 | var testhook_arg = "--testhook-dryrun" //use --testhook to run against service; use --testhook-dryrun to record test results only 13 | 14 | func Test_record_action(t *testing.T) { 15 | skipCI(t) 16 | test_engine.Record_test_result("testcases/action_test", testhook_arg, t) 17 | } 18 | 19 | func Test_record_appreg(t *testing.T) { 20 | skipCI(t) 21 | test_engine.Record_test_result("testcases/appreg_test", testhook_arg, t) 22 | } 23 | 24 | func Test_record_catalog(t *testing.T) { 25 | skipCI(t) 26 | test_engine.Record_test_result("testcases/catalog_test", testhook_arg, t) 27 | } 28 | 29 | func Test_record_collect(t *testing.T) { 30 | skipCI(t) 31 | test_engine.Record_test_result("testcases/collect_test", testhook_arg, t) 32 | } 33 | 34 | func Test_record_forwarders(t *testing.T) { 35 | skipCI(t) 36 | test_engine.Record_test_result("testcases/forwarders_test", testhook_arg, t) 37 | } 38 | 39 | func Test_record_identity(t *testing.T) { 40 | skipCI(t) 41 | test_engine.Record_test_result("testcases/identity_test", testhook_arg, t) 42 | } 43 | 44 | func Test_record_ingest(t *testing.T) { 45 | skipCI(t) 46 | test_engine.Record_test_result("testcases/ingest_test", testhook_arg, t) 47 | } 48 | 49 | func Test_record_kvstore(t *testing.T) { 50 | skipCI(t) 51 | test_engine.Record_test_result("testcases/kvstore_test", testhook_arg, t) 52 | } 53 | 54 | func Test_record_provisioner(t *testing.T) { 55 | skipCI(t) 56 | test_engine.Record_test_result("testcases/provisioner_test", testhook_arg, t) 57 | } 58 | 59 | func Test_record_search(t *testing.T) { 60 | skipCI(t) 61 | test_engine.Record_test_result("testcases/search_test", testhook_arg, t) 62 | } 63 | 64 | func Test_record_streams(t *testing.T) { 65 | skipCI(t) 66 | test_engine.Record_test_result("testcases/streams_test", testhook_arg, t) 67 | } 68 | 69 | func skipCI(t *testing.T) { 70 | if os.Getenv("CI") != "" { 71 | t.Skip("Skip testing in CI environment") 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /util/errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "io/ioutil" 23 | "net/http" 24 | ) 25 | 26 | // HTTPError is raised when status code is not 2xx 27 | type HTTPError struct { 28 | HTTPStatusCode int 29 | HTTPStatus string 30 | Message string `json:"message,omitempty"` 31 | Code string `json:"code,omitempty"` 32 | MoreInfo string `json:"moreInfo,omitempty"` 33 | Details interface{} `json:"details,omitempty"` 34 | } 35 | 36 | // This allows HTTPError to satisfy the error interface 37 | func (he *HTTPError) Error() string { 38 | jsonErrMsg, err := json.Marshal(he) 39 | if err != nil { 40 | return fmt.Sprintf("Http Error - HTTPStatusCode: [%v], HTTPStatus: %v, Error Message: %v, Error Code: %v", 41 | he.HTTPStatusCode, he.HTTPStatus, he.Message, he.Code) 42 | } 43 | return string(jsonErrMsg) 44 | } 45 | 46 | // ParseHTTPStatusCodeInResponse returns http response and HTTPError struct based on response status code 47 | func ParseHTTPStatusCodeInResponse(response *http.Response) (*http.Response, error) { 48 | if response != nil && (response.StatusCode < 200 || response.StatusCode >= 400) { 49 | httpErr := HTTPError{ 50 | HTTPStatusCode: response.StatusCode, 51 | HTTPStatus: response.Status, 52 | } 53 | if response.Body != nil { 54 | body, err := ioutil.ReadAll(response.Body) 55 | if err != nil { 56 | return response, &httpErr 57 | } 58 | err = json.Unmarshal(body, &httpErr) 59 | if err != nil { 60 | return nil, &httpErr 61 | } 62 | } 63 | return response, &httpErr 64 | } 65 | return response, nil 66 | } 67 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/action_test.expected: -------------------------------------------------------------------------------- 1 | #testcase: action create-action-email --name scloud_test_action_test --members kk@splunk.com --members aa@splunk.com 2 | REQUEST URL:action/v1beta2/actions 3 | REQUEST BODY:{{"kind":"email","name":"scloud_test_action_test","members":["kk@splunk.com","aa@splunk.com"]}} 4 | 5 | #testcase: action update-action-email-mutable --action-name scloud_test_action_test --subject "newsubject" 6 | REQUEST URL:action/v1beta2/actions/scloud_test_action_test 7 | REQUEST BODY:{{"subject":"newsubject"}} 8 | 9 | #testcase: action get-action --action-name scloud_test_action_test 10 | REQUEST URL:action/v1beta2/actions/scloud_test_action_test 11 | REQUEST BODY: 12 | 13 | #testcase: action get-public-webhook-keys 14 | REQUEST URL:action/v1beta2/webhook/keys 15 | REQUEST BODY: 16 | 17 | #testcase: action create-action-webhook --name scloud_test_action_test_wh --title newtitle --webhook-payload "{{ .name }} is a {{ .species }}" --webhook-url "https://webhook.site/test" 18 | REQUEST URL:action/v1beta2/actions 19 | REQUEST BODY:{{"kind":"webhook","name":"scloud_test_action_test_wh","webhookPayload":"{{ .name }} is a {{ .species }}","webhookUrl":"https://webhook.site/test","title":"newtitle"}} 20 | 21 | #testcase: action update-action-webhook-mutable --action-name scloud_test_action_test_wh --title "newtitle" 22 | REQUEST URL:action/v1beta2/actions/scloud_test_action_test_wh 23 | REQUEST BODY:{{"title":"newtitle"}} 24 | 25 | #testcase: action trigger-action --action-name scloud_test_action_test_wh 26 | REQUEST URL:action/v1beta2/actions/scloud_test_action_test_wh 27 | REQUEST BODY:{{"actionMetadata":{}}} 28 | 29 | #testcase: action get-action-status --action-name scloud_test_action_test --status-id CN4uIrr8qsmBVzkhlg0niUs39euOr6Jb 30 | REQUEST URL:action/v1beta2/actions/scloud_test_action_test/status/CN4uIrr8qsmBVzkhlg0niUs39euOr6Jb 31 | REQUEST BODY: 32 | 33 | #testcase: action list-actions 34 | REQUEST URL:action/v1beta2/actions 35 | REQUEST BODY: 36 | 37 | #testcase: action delete-action --action-name scloud_test_action_test 38 | REQUEST URL:action/v1beta2/actions/scloud_test_action_test 39 | REQUEST BODY: 40 | 41 | #testcase: action delete-action --action-name scloud_test_action_test_wh 42 | REQUEST URL:action/v1beta2/actions/scloud_test_action_test_wh 43 | REQUEST BODY: 44 | 45 | -------------------------------------------------------------------------------- /services/forwarders/interface_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | // Code generated by gen_interface.go. DO NOT EDIT. 18 | 19 | package forwarders 20 | 21 | import ( 22 | "net/http" 23 | ) 24 | 25 | // ServicerGenerated represents the interface for implementing all endpoints for this service 26 | type ServicerGenerated interface { 27 | /* 28 | AddCertificate - Adds a certificate to a vacant slot on a tenant. 29 | Parameters: 30 | certificate 31 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 32 | */ 33 | AddCertificate(certificate Certificate, resp ...*http.Response) (*CertificateInfo, error) 34 | /* 35 | DeleteCertificate - Removes a certificate on a particular slot on a tenant. 36 | Parameters: 37 | slot 38 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 39 | */ 40 | DeleteCertificate(slot string, resp ...*http.Response) error 41 | /* 42 | DeleteCertificates - Removes all certificates on a tenant. 43 | Parameters: 44 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 45 | */ 46 | DeleteCertificates(resp ...*http.Response) error 47 | /* 48 | ListCertificates - Returns a list of all certificates for a tenant. 49 | Parameters: 50 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 51 | */ 52 | ListCertificates(resp ...*http.Response) ([]CertificateInfo, error) 53 | } 54 | -------------------------------------------------------------------------------- /util/ticker_unit_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "reflect" 21 | "testing" 22 | "time" 23 | 24 | "github.com/stretchr/testify/assert" 25 | ) 26 | 27 | const duration = time.Duration(100) * time.Millisecond 28 | 29 | func TestCreateTicker(t *testing.T) { 30 | ticker := NewTicker(duration) 31 | assert.Equal(t, duration, ticker.duration) 32 | assert.NotNil(t, ticker.ticker) 33 | assert.False(t, ticker.running) 34 | } 35 | 36 | func TestTickerReset(t *testing.T) { 37 | ticker := NewTicker(duration) 38 | ticker.Start() 39 | tickerStatusBefore := ticker.running 40 | time.Sleep(duration) 41 | assert.Equal(t, 1, len(ticker.GetChan())) 42 | ticker.Reset() 43 | tickerStatusAfter := ticker.running 44 | assert.Equal(t, 0, len(ticker.GetChan())) 45 | assert.Equal(t, tickerStatusBefore, tickerStatusAfter) 46 | } 47 | 48 | func TestTickerStop(t *testing.T) { 49 | ticker := NewTicker(duration) 50 | ticker.Start() 51 | time.Sleep(duration) 52 | assert.Equal(t, 1, len(ticker.GetChan())) 53 | <-ticker.GetChan() 54 | assert.Equal(t, 0, len(ticker.GetChan())) 55 | ticker.Stop() 56 | time.Sleep(duration) 57 | assert.Equal(t, 0, len(ticker.GetChan())) 58 | assert.False(t, ticker.running) 59 | } 60 | 61 | func TestTickerStart(t *testing.T) { 62 | ticker := NewTicker(duration) 63 | assert.False(t, ticker.running) 64 | ticker.Start() 65 | assert.True(t, ticker.running) 66 | } 67 | 68 | func TestIsRunning(t *testing.T) { 69 | ticker := NewTicker(duration) 70 | assert.False(t, ticker.IsRunning()) 71 | } 72 | 73 | func TestTickerGetChan(t *testing.T) { 74 | ticker := NewTicker(duration) 75 | assert.Equal(t, reflect.Kind(reflect.Chan), reflect.TypeOf(ticker.GetChan()).Kind()) 76 | } 77 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/scloud/gen_version.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | /* 4 | * Copyright 2019 Splunk, Inc. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 7 | * not use this file except in compliance with the License. You may obtain 8 | * a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | * License for the specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "fmt" 23 | "os" 24 | "os/exec" 25 | "strings" 26 | "text/template" 27 | "time" 28 | ) 29 | 30 | var versionTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT. 31 | package version 32 | 33 | const ( 34 | BuildBranch = "{{ .Branch }}" 35 | BuildTime int64 = {{ .EpochSec }} 36 | Version = ScloudVersion 37 | ) 38 | `)) 39 | 40 | type templateArgs struct { 41 | Branch string 42 | EpochSec int64 43 | } 44 | 45 | // Prints an error message and exits. 46 | func fatal(msg string, args ...interface{}) { 47 | msg = fmt.Sprintf(msg, args...) 48 | fmt.Fprintf(os.Stderr, "gen_version.go: %s\n", msg) 49 | os.Exit(1) 50 | } 51 | 52 | func main() { 53 | // check the git status 54 | cmd := exec.Command("git", "status", "-s") 55 | out, err := cmd.Output() 56 | if err != nil { 57 | fatal("error running git status: %v", err) 58 | } 59 | status := strings.Trim(fmt.Sprintf("%s", out), "\n\r") 60 | fmt.Printf("The git status is: \n%s\n", status) 61 | 62 | cmd = exec.Command("git", "symbolic-ref", "--short", "HEAD") 63 | out, err = cmd.Output() 64 | branch := "detatched-head" 65 | if err == nil { 66 | branch = strings.Trim(fmt.Sprintf("%s", out), "\n\r") 67 | } 68 | 69 | _ = os.Remove("version/version.go") 70 | 71 | f, err := os.Create("version/version.go") 72 | if err != nil { 73 | fatal("error writing version.go: %v", err) 74 | } 75 | defer f.Close() 76 | 77 | err = versionTemplate.Execute(f, templateArgs{ 78 | Branch: branch, 79 | EpochSec: time.Now().Unix(), 80 | }) 81 | if err != nil { 82 | fatal("error executing template to write version.go: %v", err) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/search_test.expected: -------------------------------------------------------------------------------- 1 | #testcase: search create-job --query "from index:main" 2 | REQUEST URL:search/v2/jobs 3 | REQUEST BODY:{{"query":"from index:main","queryParameters":{}}} 4 | 5 | #testcase: search create-job --query "from index:main" --allow-side-effects true --collect-event-summary true --collect-field-summary true --collect-time-buckets true --enable-preview true 6 | REQUEST URL:search/v2/jobs 7 | REQUEST BODY:{{"query":"from index:main","allowSideEffects":true,"collectEventSummary":true,"collectFieldSummary":true,"collectTimeBuckets":true,"enablePreview":true,"queryParameters":{}}} 8 | 9 | #testcase: search get-job --sid f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll 10 | REQUEST URL:search/v2/jobs/f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll 11 | REQUEST BODY: 12 | 13 | #testcase: search list-jobs 14 | REQUEST URL:search/v2/jobs 15 | REQUEST BODY: 16 | 17 | #testcase: search list-results --sid f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll 18 | REQUEST URL:search/v2/jobs/f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll/results 19 | REQUEST BODY: 20 | 21 | #testcase: search update-job --sid f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll --status finalized 22 | REQUEST URL:search/v2/jobs/f06b0ce82ee39c42a1384a580e0c043c_1582744223402696872_xdjll 23 | REQUEST BODY:{{"status":"finalized"}} 24 | 25 | #testcase: search list-events-summary --sid "0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn" 26 | REQUEST URL:search/v2/jobs/0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn/timeline-metadata/auto/events-summary 27 | REQUEST BODY: 28 | 29 | #testcase: search list-fields-summary --sid "0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn" 30 | REQUEST URL:search/v2/jobs/0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn/timeline-metadata/auto/fields-summary 31 | REQUEST BODY: 32 | 33 | #testcase: search list-preview-results --sid "0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn" 34 | REQUEST URL:search/v2/jobs/0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn/results-preview 35 | REQUEST BODY: 36 | 37 | #testcase: search list-time-buckets --sid "0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn" 38 | REQUEST URL:search/v2/jobs/0da44a16e80195c39ac3cf861bb0c7b2_1582745278455769675_l2wcn/timeline-metadata/auto/time-buckets 39 | REQUEST BODY: 40 | 41 | -------------------------------------------------------------------------------- /services/kvstore/model_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2022 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | * 16 | * KV Store API 17 | * 18 | * With the Splunk Cloud KV store service in Splunk Cloud Services, you can save and retrieve data within your Splunk Cloud apps, enabling you to manage and maintain state in your application. 19 | * 20 | * API version: v1beta1.2 (recommended default) 21 | * Generated by: OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. 22 | */ 23 | 24 | package kvstore 25 | 26 | type ErrorResponse struct { 27 | // Internal status code of the error. 28 | Code string `json:"code"` 29 | // Detailed error message. 30 | Message string `json:"message"` 31 | } 32 | 33 | type IndexDefinition struct { 34 | Fields []IndexFieldDefinition `json:"fields"` 35 | // The name of the index. 36 | Name string `json:"name"` 37 | } 38 | 39 | type IndexDescription struct { 40 | // The collection name. 41 | Collection *string `json:"collection,omitempty"` 42 | Fields []IndexFieldDefinition `json:"fields,omitempty"` 43 | // The name of the index. 44 | Name *string `json:"name,omitempty"` 45 | } 46 | 47 | type IndexFieldDefinition struct { 48 | // The sort direction for the indexed field. 49 | Direction int32 `json:"direction"` 50 | // The name of the field to index. 51 | Field string `json:"field"` 52 | } 53 | 54 | type PingResponse struct { 55 | // Database status. 56 | Status PingResponseStatus `json:"status"` 57 | // If database is not healthy, detailed error message. 58 | ErrorMessage *string `json:"errorMessage,omitempty"` 59 | } 60 | 61 | // PingResponseStatus : Database status. 62 | type PingResponseStatus string 63 | 64 | // List of PingResponseStatus 65 | const ( 66 | PingResponseStatusHealthy PingResponseStatus = "healthy" 67 | PingResponseStatusUnhealthy PingResponseStatus = "unhealthy" 68 | PingResponseStatusUnknown PingResponseStatus = "unknown" 69 | ) 70 | 71 | type Record struct { 72 | // Key of the resulting record. 73 | Key string `json:"_key"` 74 | // User of the resulting record. 75 | User string `json:"_user"` 76 | } 77 | -------------------------------------------------------------------------------- /cicd/publish/scloud/publish_github.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [ "${CI}" != "true" ] ; then 4 | echo "Exiting: $0 can only be run from the CI system." 5 | exit 1 6 | fi 7 | 8 | if [ -z "${GITHUB_TOKEN}" ] ; then 9 | echo "No \$GITHUB_TOKEN set, exiting ..." 10 | exit 1 11 | fi 12 | 13 | if [ -z "${GITHUB_ORG}" ] ; then 14 | GITHUB_ORG=splunk 15 | echo "No \$GITHUB_ORG set, using ${GITHUB_ORG} by default ..." 16 | fi 17 | 18 | if [ -z "${GITHUB_PROJECT}" ] ; then 19 | # We are moving scloud into the splunk-cloud-sdk-go repo for public distribution, 20 | # until that happens officially we will publish scloud artifacts there from this repo 21 | GITHUB_PROJECT=splunk-cloud-sdk-go 22 | echo "No \$GITHUB_PROJECT set, using ${GITHUB_PROJECT} by default ..." 23 | fi 24 | GITHUB_REPO="https://github.com/${GITHUB_ORG}/${GITHUB_PROJECT}" 25 | 26 | if [[ "$(uname)" == "Darwin" ]] ; then 27 | # MacOS 28 | SED_FLG="-E" 29 | else 30 | # Linux 31 | SED_FLG="-r" 32 | fi 33 | # Get release version from services/client_info.go e.g. v0.9.2 34 | RELEASE_TAG=v$(cat services/client_info.go | sed ${SED_FLG} -n 's/const Version = "([0-9]+\.[0-9]+\.[0-9]+.*)"/\1/p') 35 | if [ -n "${OVERRIDE_RELEASE_TAG}" ] ; then 36 | echo "\$OVERRIDE_RELEASE_TAG was set so uploading cross-compiled artifacts to ${OVERRIDE_RELEASE_TAG} rather than the default for this tag (${RELEASE_TAG}) ..." 37 | RELEASE_TAG="${OVERRIDE_RELEASE_TAG}" 38 | fi 39 | 40 | echo "Installing github-release ..." 41 | go get github.com/aktau/github-release 42 | 43 | echo "Checking to make sure release of ${RELEASE_TAG} exists at ${GITHUB_REPO}/releases ..." 44 | github-release info --user "${GITHUB_ORG}" --repo "${GITHUB_PROJECT}" --tag "${RELEASE_TAG}" 45 | 46 | echo "Uploading (replacing if files already existed) cross-compiled archive artifacts to existing release of ${RELEASE_TAG} at ${GITHUB_REPO}/releases ..." 47 | echo "" 48 | artifacts=bin/cross-compiled_scloud/archive/* 49 | for artifact in $artifacts ; do 50 | echo "Uploading ${artifact} ..." 51 | github-release upload --replace --user "${GITHUB_ORG}" --repo "${GITHUB_PROJECT}" --tag "${RELEASE_TAG}" --file "${artifact}" --name "$(basename ${artifact})" 52 | done 53 | echo "" 54 | echo "Success!" 55 | 56 | echo "Uploading (replacing if files already existed) cross-compiled scloud archive artifacts to existing release of ${RELEASE_TAG} at ${GITHUB_REPO}/releases ..." 57 | echo "" 58 | artifacts=bin/cross-compiled_scloud/archive/* 59 | for artifact in $artifacts ; do 60 | echo "Uploading ${artifact} ..." 61 | github-release upload --replace --user "${GITHUB_ORG}" --repo "${GITHUB_PROJECT}" --tag "${RELEASE_TAG}" --file "${artifact}" --name "$(basename ${artifact})" 62 | done 63 | echo "" 64 | echo "Success!" -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/streams_test: -------------------------------------------------------------------------------- 1 | streams compile --input-datafile testcases/test_stream_compile.spl 2 | 3 | streams create-pipeline --name test-passthrough --input-datafile testcases/test_stream_create_pipeline.json --bypass-validation true --description "A passthrough pipeline" 4 | streams validate-pipeline --input-datafile testcases/test_stream_validate_pipeline.json 5 | streams update-pipeline --id 57cc9796-bb08-48dd-9f0e-f269fc762eda --input-datafile testcases/test_stream_patch_pipeline.json --description "Updated Integration Test Pipeline testPipelinfe1582068339" --name "updatedtestPipelinfe1582068339" 6 | streams patch-pipeline --id 57cc9796-bb08-48dd-9f0e-f269fc762eda --name passthrough --input-datafile testcases/test_stream_patch_pipeline.json --bypass-validation true --description "Patched pipeline" 7 | 8 | streams reactivate-pipeline --id 57cc9796-bb08-48dd-9f0e-f269fc762eda 9 | 10 | streams list-pipelines 11 | streams get-pipeline --id 57cc9796-bb08-48dd-9f0e-f269fc762eda 12 | streams get-pipelines-status 13 | streams activate-pipeline --id 57cc9796-bb08-48dd-9f0e-f269fc762eda 14 | streams deactivate-pipeline --id 57cc9796-bb08-48dd-9f0e-f269fc762eda 15 | streams delete-pipeline --id 280afcdd-cca1-4cff-b643-9d3295a70075 16 | 17 | streams list-connectors 18 | streams list-connections 19 | 20 | streams create-connection --connector-id 879837b0-cabf-4bc2-8589-fcc4dad753e7 --data "{\"splunk-url\":\"https://hostname.port\", \"token\":\"mytoken\"}" --description "newconnection" --name "myconnection" 21 | streams update-connection --connection-id 879837b0-cabf-4bc2-8589-fcc4dad753e7 --data "{\"splunk-url\":\"https://hostname.port\", \"token\":\"mytoken\"}" --description "newconnection" --name "myconnection" 22 | streams put-connection --connection-id 879837b0-cabf-4bc2-8589-fcc4dad753e7 --data "{\"splunk-url\":\"https://hostname.port\", \"token\":\"mytoken\"}" --description "newconnection" --name "myconnection" 23 | 24 | streams delete-connection --connection-id 6c7896b2-a53c-4078-b757-07e80739d91e 25 | 26 | streams get-registry --local false 27 | 28 | streams create-template --input-datafile testcases/test_stream_create_template.json --name testTemplate1582068227 --description "integration test template" 29 | streams list-templates 30 | streams get-template --template-id 680db4a4-d733-428a-a0a0-9eac9f3e8252 31 | 32 | #Deprecated in v3beta1 33 | streams create-group --input-datafile testcases/test_stream_create_group.json 34 | 35 | streams get-input-schema --node-uuid "3682041e-1814-4bd7-8e60-5c889b822585" --target-port-name "input" --input-datafile testcases/test_stream_get_input_schema.json 36 | 37 | # go sdk dosesn't have a working example for GetOutputSchema endpoint 38 | #streams get-output-schema --node-uuid "3682041e-1814-4bd7-8e60-5c889b822585" --target-port-name "output" --input-datafile testcases/test_stream_get_output_schema.json 39 | 40 | -------------------------------------------------------------------------------- /util/roundtripper.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | "net/http/httputil" 23 | ) 24 | 25 | // Logger compatible with standard "log" library 26 | type Logger interface { 27 | Print(v ...interface{}) 28 | } 29 | 30 | // SdkTransport is to define a transport RoundTripper with user-defined logger 31 | type SdkTransport struct { 32 | transport http.RoundTripper 33 | logger Logger 34 | } 35 | 36 | // 80 chars wide 37 | const divider = "================================================================================" 38 | 39 | // RoundTrip implements the RoundTripper interface 40 | func (st *SdkTransport) RoundTrip(request *http.Request) (*http.Response, error) { 41 | st.logger.Print("\n") 42 | requestDump, err := httputil.DumpRequest(request, true) 43 | if err != nil { 44 | st.logger.Print(fmt.Sprintf("%s\nRequest error:\n%s\n%s\n", divider, divider, err.Error())) 45 | return nil, err 46 | } 47 | 48 | st.logger.Print(fmt.Sprintf("%s\nRequest:\n%s\n", divider, string(requestDump))) 49 | 50 | response, err := st.transport.RoundTrip(request) 51 | if response != nil { 52 | st.logger.Print(fmt.Sprintf("%s\nResponse from: %s %s [%d]\nRequest ID: %s\n", divider, request.Method, request.URL, response.StatusCode, response.Header.Get("X-Request-ID"))) 53 | } 54 | if err != nil { 55 | st.logger.Print(fmt.Sprintf("%s\nRequest error:\n%s\n", divider, err.Error())) 56 | return response, err 57 | } 58 | 59 | responseDump, err := httputil.DumpResponse(response, true) 60 | if err != nil { 61 | st.logger.Print(fmt.Sprintf("%s\nResponse error:\n%s\n", divider, err.Error())) 62 | return response, err 63 | } 64 | 65 | st.logger.Print(fmt.Sprintf("%s\nResponse:\n%s\n%s\n", divider, string(responseDump), divider)) 66 | 67 | return response, err 68 | } 69 | 70 | // NewSdkTransport Creates a RoundTripper with user defined logger 71 | func NewSdkTransport(logger Logger) *SdkTransport { 72 | return NewCustomSdkTransport(logger, &http.Transport{}) 73 | } 74 | 75 | // NewCustomSdkTransport Creates a RoundTripper with user defined logger and http.Transport 76 | func NewCustomSdkTransport(logger Logger, transport *http.Transport) *SdkTransport { 77 | return &SdkTransport{logger: logger, transport: transport} 78 | } 79 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/appreg_test: -------------------------------------------------------------------------------- 1 | appreg create-app-native --name scloud_test_appreg_name1 --title scloud_test_appreg_title1 --description scloud_test_appreg_description --redirect-urls https://scloud.test.appreg.redirect1.url.com,https://scloud.test.appreg.redirect2.url.com --login-url https://scloud.test.appreg.login.url.com --logo-url https://scloud.test.appreg.logo.url.com --setup-url https://scloud.test.appreg.setup.url.com --user-permissions-filter scloud_test_appreg_resource1:scloud_test_appreg_scope1.scloud_test_appreg_scope2,scloud_test_appreg_resource2:scloud_test_appreg_scope3.scloud_test_appreg_scope4 --app-principal-permissions scloud_test_appreg_resource1:scloud_test_appreg_scope1.scloud_test_appreg_scope2,scloud_test_appreg_resource2:scloud_test_appreg_scope3.scloud_test_appreg_scope4 2 | appreg create-app-service --name scloud_test_appreg_name2 --title scloud_test_appreg_title2 --description scloud_test_appreg_description --redirect-urls https://scloud.test.appreg.redirect1.url.com,https://scloud.test.appreg.redirect2.url.com --login-url https://scloud.test.appreg.login.url.com --logo-url https://scloud.test.appreg.logo.url.com --setup-url https://scloud.test.appreg.setup.url.com --user-permissions-filter scloud_test_appreg_resource1:scloud_test_appreg_scope1.scloud_test_appreg_scope2,scloud_test_appreg_resource2:scloud_test_appreg_scope3.scloud_test_appreg_scope4 --app-principal-permissions scloud_test_appreg_resource1:scloud_test_appreg_scope1.scloud_test_appreg_scope2,scloud_test_appreg_resource2:scloud_test_appreg_scope3.scloud_test_appreg_scope4 3 | 4 | appreg update-app --app-name scloud_test_appreg_name1 --title scloud_test_appreg_title_updated --description scloud_test_appreg_description_updated --redirect-urls https://scloud.test.appreg.redirect.updated.url.com,https://scloud.test.appreg.redirect2.updated.url.com --login-url https://scloud.test.appreg.login.updated.url.com --logo-url https://scloud.test.appreg.logo.updated.url.com --setup-url https://scloud.test.appreg.setup.updated.url.com --user-permissions-filter scloud_test_appreg_resource1:scloud_test_appreg_scope1.scloud_test_appreg_scope2,scloud_test_appreg_resource2:scloud_test_appreg_scope3.scloud_test_appreg_scope4 --app-principal-permissions scloud_test_appreg_resource1:scloud_test_appreg_scope1.scloud_test_appreg_scope2,scloud_test_appreg_resource2:scloud_test_appreg_scope3.scloud_test_appreg_scope4 5 | 6 | appreg get-app --app-name scloud_test_appreg_name1 7 | appreg list-apps 8 | 9 | appreg create-subscription --app-name scloud_test_appreg_name1 10 | appreg get-subscription --app-name scloud_test_appreg_name1 11 | appreg list-app-subscriptions --app-name scloud_test_appreg_name1 12 | appreg list-subscriptions 13 | appreg delete-subscription --app-name scloud_test_appreg_name1 14 | 15 | appreg get-keys 16 | appreg rotate-secret --app-name scloud_test_appreg_name2 17 | 18 | appreg delete-app --app-name scloud_test_appreg_name1 19 | appreg delete-app --app-name scloud_test_appreg_name2 20 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/kvstore_test.expected: -------------------------------------------------------------------------------- 1 | #testcase: kvstore create-index --name myindex --fields "[{\"direction\":-1,\"field\":\"integ_testField1\"}]" --collection gomod1582754557.gointegdskvidx_1582754557 2 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/indexes 3 | REQUEST BODY:{{"fields":[{"direction":-1,"field":"integ_testField1"}],"name":"myindex"}} 4 | 5 | #testcase: kvstore delete-index --collection gomod1582754557.gointegdskvidx_1582754557 --index myindex 6 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/indexes/myindex 7 | REQUEST BODY: 8 | 9 | #testcase: kvstore list-indexes --collection gomod1582754557.gointegdskvidx_1582754557 10 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/indexes 11 | REQUEST BODY: 12 | 13 | #testcase: kvstore ping 14 | REQUEST URL:kvstore/v1beta1/ping 15 | REQUEST BODY: 16 | 17 | #testcase: kvstore insert-record --collection gomod1582754557.gointegdskvidx_1582754557 --body "{\"capacity_gb\": 8}" 18 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557 19 | REQUEST BODY:{{"capacity_gb":8}} 20 | 21 | #testcase: kvstore list-records --collection gomod1582754557.gointegdskvidx_1582754557 22 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557 23 | REQUEST BODY: 24 | 25 | #testcase: kvstore insert-records --collection gomod1582754557.gointegdskvidx_1582754557 --body "[{\"capacity_gb\": 8},{\"capacity_gb\": 7}]" 26 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/batch 27 | REQUEST BODY:{[{"capacity_gb":8},{"capacity_gb":7}]} 28 | 29 | #testcase: kvstore put-record --collection gomod1582754557.gointegdskvidx_1582754557 --key "5e58525673875400011ffb13" --body "{\"capacity_gb\": 8}" 30 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/records/%225e58525673875400011ffb13%22 31 | REQUEST BODY:{{"capacity_gb":8}} 32 | 33 | #testcase: kvstore query-records --collection gomod1582754557.gointegdskvidx_1582754557 34 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/query 35 | REQUEST BODY: 36 | 37 | #testcase: kvstore get-record-by-key --collection gomod1582754557.gointegdskvidx_1582754557 --key "5e58525673875400011ffb13" 38 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/records/5e58525673875400011ffb13 39 | REQUEST BODY: 40 | 41 | #testcase: kvstore delete-record-by-key --collection gomod1582754557.gointegdskvidx_1582754557 --key "5e58525673875400011ffb13" 42 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/records/5e58525673875400011ffb13 43 | REQUEST BODY: 44 | 45 | #testcase: kvstore delete-records --collection gomod1582754557.gointegdskvidx_1582754557 46 | REQUEST URL:kvstore/v1beta1/collections/gomod1582754557.gointegdskvidx_1582754557/query 47 | REQUEST BODY: 48 | 49 | -------------------------------------------------------------------------------- /services/ingest/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | //This file contains interfaces that can't be auto-generated from codegen and interfaces that are auto-generated from codegen 18 | 19 | package ingest 20 | 21 | import ( 22 | "io" 23 | "net/http" 24 | ) 25 | 26 | // Servicer represents the interface for implementing all endpoints for this service 27 | type Servicer interface { 28 | //interfaces that cannot be auto-generated from codegen 29 | /* 30 | NewBatchEventsSenderWithMaxAllowedError initializes a BatchEventsSender to collect events and send them as a single 31 | batched request when a maximum event batch size, time interval, or maximum payload size is reached. It also 32 | validates the user input for BatchEventSender. 33 | Parameters: 34 | batchSize: maximum number of events to reach before sending the batch, default maximum is 500 35 | interval: milliseconds to wait before sending the batch if other conditions have not been met 36 | dataSize: bytes that the overall payload should not exceed before sending, default maximum is 1040000 ~1MiB 37 | maxErrorsAllowed: number of errors after which the BatchEventsSender will stop 38 | */ 39 | NewBatchEventsSenderWithMaxAllowedError(batchSize int, interval int64, dataSize int, maxErrorsAllowed int) (*BatchEventsSender, error) 40 | /* 41 | NewBatchEventsSender initializes a BatchEventsSender to collect events and send them as a single batched 42 | request when a maximum event batch size, time interval, or maximum payload size is reached. 43 | Parameters: 44 | batchSize: maximum number of events to reach before sending the batch, default maximum is 500 45 | interval: milliseconds to wait before sending the batch if other conditions have not been met 46 | payLoadSize: bytes that the overall payload should not exceed before sending, default maximum is 1040000 ~1MiB 47 | */ 48 | NewBatchEventsSender(batchSize int, interval int64, payLoadSize int) (*BatchEventsSender, error) 49 | /* 50 | UploadFilesStream - Upload stream of io.Reader. 51 | Parameters: 52 | stream 53 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 54 | */ 55 | UploadFilesStream(stream io.Reader, resp ...*http.Response) error 56 | 57 | //interfaces that are auto-generated in interface_generated.go 58 | ServicerGenerated 59 | } 60 | -------------------------------------------------------------------------------- /services/ingest/new_batch_events_sender.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Splunk Ingest Service 3 | * 4 | */ 5 | 6 | package ingest 7 | 8 | import ( 9 | "sync" 10 | "time" 11 | 12 | "errors" 13 | 14 | "github.com/splunk/splunk-cloud-sdk-go/util" 15 | ) 16 | 17 | /* 18 | NewBatchEventsSenderWithMaxAllowedError initializes a BatchEventsSender to collect events and send them as a single 19 | batched request when a maximum event batch size, time interval, or maximum payload size is reached. It also 20 | validates the user input for BatchEventSender. 21 | Parameters: 22 | batchSize: maximum number of events to reach before sending the batch, default maximum is 500 23 | interval: milliseconds to wait before sending the batch if other conditions have not been met 24 | dataSize: bytes that the overall payload should not exceed before sending, default maximum is 1040000 ~1MiB 25 | maxErrorsAllowed: number of errors after which the BatchEventsSender will stop 26 | */ 27 | func (s *Service) NewBatchEventsSenderWithMaxAllowedError(batchSize int, interval int64, dataSize int, maxErrorsAllowed int) (*BatchEventsSender, error) { 28 | // Rather than return a super general error for both it will block on batchSize first 29 | if batchSize == 0 { 30 | return nil, errors.New("batchSize cannot be 0") 31 | } 32 | if batchSize > eventCount { 33 | batchSize = eventCount 34 | } 35 | if interval == 0 { 36 | return nil, errors.New("interval cannot be 0") 37 | } 38 | if dataSize == 0 { 39 | dataSize = payLoadSize 40 | } 41 | 42 | if maxErrorsAllowed < 0 { 43 | maxErrorsAllowed = 1 44 | } 45 | 46 | eventsChan := make(chan Event, batchSize) 47 | eventsQueue := make([]Event, 0, batchSize) 48 | quit := make(chan struct{}, 1) 49 | ticker := util.NewTicker(time.Duration(interval) * time.Millisecond) 50 | var wg sync.WaitGroup 51 | errorChan := make(chan struct{}, maxErrorsAllowed) 52 | 53 | batchEventsSender := &BatchEventsSender{ 54 | BatchSize: batchSize, 55 | PayLoadBytes: dataSize, 56 | EventsChan: eventsChan, 57 | EventsQueue: eventsQueue, 58 | EventService: s, 59 | QuitChan: quit, 60 | IngestTicker: ticker, 61 | WaitGroup: &wg, 62 | ErrorChan: errorChan, 63 | IsRunning: false, 64 | chanWaitMillis: 300, 65 | callbackFunc: nil, 66 | } 67 | 68 | return batchEventsSender, nil 69 | } 70 | 71 | /* 72 | NewBatchEventsSender initializes a BatchEventsSender to collect events and send them as a single batched 73 | request when a maximum event batch size, time interval, or maximum payload size is reached. 74 | Parameters: 75 | batchSize: maximum number of events to reach before sending the batch, default maximum is 500 76 | interval: milliseconds to wait before sending the batch if other conditions have not been met 77 | payLoadSize: bytes that the overall payload should not exceed before sending, default maximum is 1040000 ~1MiB 78 | */ 79 | func (s *Service) NewBatchEventsSender(batchSize int, interval int64, payLoadSize int) (*BatchEventsSender, error) { 80 | return s.NewBatchEventsSenderWithMaxAllowedError(batchSize, interval, payLoadSize, 1) 81 | } 82 | -------------------------------------------------------------------------------- /cicd/scripts/build_cross_compile_scloud.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | 4 | SCLOUD_SRC_PATH=./cmd/scloud/cmd/scloud 5 | 6 | if [[ -z "${SCLOUD_SRC_PATH}" ]] ; then 7 | echo "SCLOUD_SRC_PATH must be set, exiting ..." 8 | exit 1 9 | fi 10 | 11 | if [[ "$(uname)" == "Darwin" ]] ; then 12 | # MacOS 13 | SED_FLG="-E" 14 | else 15 | # Linux 16 | SED_FLG="-r" 17 | 18 | fi 19 | 20 | BUILD_TARGETS_ARCH=( 386 amd64 arm64) 21 | BUILD_TARGETS_OS=( darwin linux windows ) 22 | TARGET_ROOT_DIR=bin/cross-compiled_scloud 23 | ARCHIVE_DIR=${TARGET_ROOT_DIR}/archive 24 | TAG=$(git describe --abbrev=0 --tags) 25 | 26 | rm -fr ${TARGET_ROOT_DIR} 27 | mkdir -p ${ARCHIVE_DIR} 28 | 29 | for os in ${BUILD_TARGETS_OS[@]} 30 | do 31 | for arch in ${BUILD_TARGETS_ARCH[@]} 32 | do 33 | if [[ 'windows' == ${os} ]] 34 | then 35 | program_name='scloud.exe' 36 | else 37 | program_name='scloud' 38 | fi 39 | if [[ 'darwin' == ${os} ]] && [[ '386' == ${arch} ]] 40 | then 41 | echo "Skipping darwin/386, no longer supported in go 1.15+" 42 | continue 43 | fi 44 | target_dir=${TARGET_ROOT_DIR}/${os}_${arch} 45 | mkdir -p ${target_dir} 46 | target_file=${target_dir}/${program_name} 47 | echo "Building ${target_file}"; 48 | # The -s flag strips debug symbols from Linux, -w from DWARF (darwin). This reduces binary size by about half. 49 | env GOOS=${os} GOARCH=${arch} GO111MODULE=on go build -ldflags "-s -w" -a -mod=readonly -o ${target_file} ${SCLOUD_SRC_PATH} 50 | scloud_version=v$(cat cmd/scloud/cmd/scloud/version/client_info.go | sed ${SED_FLG} -n 's/const ScloudVersion = "([0-9]+\.[0-9]+\.[0-9]+.*)"/\1/p') 51 | archive_file=${PWD}/${ARCHIVE_DIR}/scloud_${scloud_version}_${os}_${arch} 52 | 53 | if [[ 'windows' == ${os} ]] 54 | then 55 | pushd ${target_dir} 56 | zip ${archive_file}.zip ${program_name} 57 | popd 58 | else 59 | tar -C ${target_dir} -czvf ${archive_file}.tar.gz ${program_name} 60 | fi 61 | echo "" 62 | done 63 | done 64 | 65 | if [[ "$(uname -m)" == "x86_64" ]] ; then 66 | myarch=amd64 67 | else 68 | myarch=386 69 | fi 70 | if [[ "$OS" == "Windows_NT" ]] ; then 71 | myos=windows 72 | program_name='scloud.exe' 73 | else 74 | program_name='scloud' 75 | if [[ "$(uname -s)" == "Linux" ]] ; then 76 | myos=linux 77 | else 78 | myos=darwin 79 | fi 80 | fi 81 | 82 | myscloud="${TARGET_ROOT_DIR}/${myos}_${myarch}/${program_name}" 83 | echo "Testing binary for this environment: ${myscloud} ..." 84 | if ! [[ -f "${myscloud}" ]] ; then 85 | echo "File not found: ${myscloud} , exiting ..." 86 | exit 1 87 | fi 88 | ${myscloud} version 89 | status=$? 90 | if [[ "${status}" -gt "0" ]] ; then 91 | echo "Error running \"${myscloud} version\", exiting ..." 92 | exit 1 93 | fi 94 | echo "Success." 95 | echo "" 96 | 97 | echo "Package archives created: " 98 | echo "" 99 | archives=$(ls ${ARCHIVE_DIR}) 100 | echo "${archives}" -------------------------------------------------------------------------------- /util/errors_unit_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "bytes" 21 | "io/ioutil" 22 | "net/http" 23 | "testing" 24 | 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestParseHTTPStatusCodeInResponseOKResponse(t *testing.T) { 29 | httpResp := &http.Response{ 30 | StatusCode: 201, 31 | } 32 | if _, err := ParseHTTPStatusCodeInResponse(httpResp); err != nil { 33 | t.Errorf("ParseHTTPStatusCodeInResponse expected to not return error for good responses, got %v", err) 34 | } 35 | } 36 | 37 | func TestParseHTTPStatusCodeInResponseNilResponse(t *testing.T) { 38 | if _, err := ParseHTTPStatusCodeInResponse(nil); err != nil { 39 | t.Errorf("ParseHTTPStatusCodeInResponse expected to not return error for good responses, got %v", err) 40 | } 41 | } 42 | 43 | func TestParseHTTPStatusCodeInResponseBadResponseNilBody(t *testing.T) { 44 | httpResp := &http.Response{ 45 | StatusCode: 400, 46 | Status: "400 Bad Request", 47 | Body: nil, 48 | } 49 | expectErrMsg := `{"HTTPStatusCode":400,"HTTPStatus":"400 Bad Request"}` 50 | _, err := ParseHTTPStatusCodeInResponse(httpResp) 51 | assert.Equal(t, 400, err.(*HTTPError).HTTPStatusCode) 52 | assert.Equal(t, "400 Bad Request", err.(*HTTPError).HTTPStatus) 53 | assert.Equal(t, err.Error(), expectErrMsg) 54 | } 55 | 56 | func TestParseHTTPStatusCodeInResponseEmptyBody(t *testing.T) { 57 | httpResp := &http.Response{ 58 | StatusCode: 400, 59 | Status: "400 Bad Request", 60 | Body: ioutil.NopCloser(bytes.NewReader([]byte(`{}`))), 61 | } 62 | expectErrMsg := `{"HTTPStatusCode":400,"HTTPStatus":"400 Bad Request"}` 63 | _, err := ParseHTTPStatusCodeInResponse(httpResp) 64 | assert.Equal(t, 400, err.(*HTTPError).HTTPStatusCode) 65 | assert.Equal(t, "400 Bad Request", err.(*HTTPError).HTTPStatus) 66 | assert.Equal(t, err.Error(), expectErrMsg) 67 | } 68 | 69 | func TestParseHTTPStatusCodeInResponseBodyMsg(t *testing.T) { 70 | httpResp := &http.Response{ 71 | StatusCode: 400, 72 | Status: "400 Bad Request", 73 | Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"code": "1017","message": "Validation Failed"}`))), 74 | } 75 | expectErrMsg := `{"HTTPStatusCode":400,"HTTPStatus":"400 Bad Request","message":"Validation Failed","code":"1017"}` 76 | _, err := ParseHTTPStatusCodeInResponse(httpResp) 77 | assert.Equal(t, 400, err.(*HTTPError).HTTPStatusCode) 78 | assert.Equal(t, "400 Bad Request", err.(*HTTPError).HTTPStatus) 79 | assert.Equal(t, "1017", err.(*HTTPError).Code) 80 | assert.Equal(t, "Validation Failed", err.(*HTTPError).Message) 81 | assert.Equal(t, err.Error(), expectErrMsg) 82 | } 83 | -------------------------------------------------------------------------------- /cicd/docs/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #################################################################################################### 4 | # Check for required env vars 5 | #################################################################################################### 6 | if [[ "${CI}" != "true" ]] ; then 7 | echo "Exiting: $0 can only be run from the CI system." 8 | exit 1 9 | fi 10 | if [[ -z "${ARTIFACT_USERNAME}" ]] ; then 11 | echo "ARTIFACT_USERNAME must be set, exiting ..." 12 | exit 1 13 | fi 14 | if [[ -z "${ARTIFACT_PASSWORD}" ]] ; then 15 | echo "ARTIFACT_PASSWORD must be set, exiting ..." 16 | exit 1 17 | fi 18 | if [[ -z "${ARTIFACTORY_NPM_REGISTRY}" ]] ; then 19 | echo "ARTIFACTORY_NPM_REGISTRY must be set, exiting ..." 20 | exit 1 21 | fi 22 | 23 | #################################################################################################### 24 | # Set platform-specific sed extended syntax flag 25 | #################################################################################################### 26 | if [[ "$(uname)" == "Darwin" ]] ; then 27 | # MacOS 28 | SED_FLG="-E" 29 | else 30 | # Linux 31 | SED_FLG="-r" 32 | fi 33 | 34 | #################################################################################################### 35 | # Get release version from services/client_info.go e.g. 0.9.2 36 | #################################################################################################### 37 | NEW_VERSION=$(cat services/client_info.go | sed ${SED_FLG} -n 's/const Version = "([0-9]+\.[0-9]+\.[0-9]+.*)"/\1/p') 38 | if [[ -z "${NEW_VERSION}" ]] ; then 39 | echo "error setting NEW_VERSION from services/client_info.go, version must be set to match: const Version = \"([0-9]+\.[0-9]+\.[0-9]+.*)\" (e.g. const Version = \"0.8.3\") but format found is:\n\n$(cat services/client_info.go)\n\n..." 40 | exit 1 41 | fi 42 | 43 | echo "Publishing docs for v${NEW_VERSION} ..." 44 | 45 | # Run from ci/docs directory 46 | cd "$(dirname "$0")" 47 | #################################################################################################### 48 | # Write a package.json file, this is needed by @splunk/cicd-tools even though this isn't js 49 | #################################################################################################### 50 | rm package.json 51 | PACKAGE_JSON="{ 52 | \"name\": \"@splunk/splunk-cloud-sdk-go\", 53 | \"version\": \"${NEW_VERSION}\", 54 | \"description\": \"Splunk Cloud SDK for Go\" 55 | }" 56 | echo ${PACKAGE_JSON} > package.json 57 | rm -rf build/ 58 | #################################################################################################### 59 | # Install @splunk/cicd-tools from artifactory 60 | #################################################################################################### 61 | npm add --no-save @splunk/cicd-tools --registry "${ARTIFACTORY_NPM_REGISTRY}" 62 | #################################################################################################### 63 | # Publish docs to artifactory with @splunk/cicd-tools/cicd-publish-docs 64 | #################################################################################################### 65 | npx cicd-publish-docs --force ../../docs/ 66 | echo "Docs built and packaged into $(dirname "$0")/build" -------------------------------------------------------------------------------- /cmd/scloud/pkg/forwarders/forwarders-gen.go: -------------------------------------------------------------------------------- 1 | // Package forwarders -- generated by scloudgen 2 | // !! DO NOT EDIT !! 3 | // 4 | package forwarders 5 | 6 | import ( 7 | "encoding/json" 8 | "fmt" 9 | "io/ioutil" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/auth" 13 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/flags" 14 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/jsonx" 15 | model "github.com/splunk/splunk-cloud-sdk-go/services/forwarders" 16 | ) 17 | 18 | // AddCertificate Adds a certificate to a vacant slot on a tenant. 19 | func AddCertificate(cmd *cobra.Command, args []string) error { 20 | 21 | client, err := auth.GetClient() 22 | if err != nil { 23 | return err 24 | } 25 | // Parse all flags 26 | 27 | var inputDatafile string 28 | err = flags.ParseFlag(cmd.Flags(), "input-datafile", &inputDatafile) 29 | if err != nil { 30 | return fmt.Errorf(`error parsing "input-datafile": ` + err.Error()) 31 | } 32 | var pem string 33 | //porcess customized FileInput 34 | bytes, err := ioutil.ReadFile(inputDatafile) 35 | if err != nil { 36 | return err 37 | } 38 | err = json.Unmarshal(bytes, &pem) 39 | if err != nil { 40 | // If failed to parse as JSON, try reading as simple string 41 | pem = string(bytes) 42 | } 43 | // Form the request body 44 | generated_request_body := model.Certificate{ 45 | 46 | Pem: pem, 47 | } 48 | 49 | // Silence Usage 50 | cmd.SilenceUsage = true 51 | 52 | resp, err := client.ForwardersService.AddCertificate(generated_request_body) 53 | if err != nil { 54 | return err 55 | } 56 | jsonx.Pprint(cmd, resp) 57 | return nil 58 | } 59 | 60 | // DeleteCertificate Removes a certificate on a particular slot on a tenant. 61 | func DeleteCertificate(cmd *cobra.Command, args []string) error { 62 | 63 | client, err := auth.GetClient() 64 | if err != nil { 65 | return err 66 | } 67 | // Parse all flags 68 | 69 | var slot string 70 | err = flags.ParseFlag(cmd.Flags(), "slot", &slot) 71 | if err != nil { 72 | return fmt.Errorf(`error parsing "slot": ` + err.Error()) 73 | } 74 | 75 | // Silence Usage 76 | cmd.SilenceUsage = true 77 | 78 | err = client.ForwardersService.DeleteCertificate(slot) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | return nil 84 | } 85 | 86 | // DeleteCertificates Removes all certificates on a tenant. 87 | func DeleteCertificates(cmd *cobra.Command, args []string) error { 88 | 89 | client, err := auth.GetClient() 90 | if err != nil { 91 | return err 92 | } 93 | 94 | // Silence Usage 95 | cmd.SilenceUsage = true 96 | 97 | err = client.ForwardersService.DeleteCertificates() 98 | if err != nil { 99 | return err 100 | } 101 | 102 | return nil 103 | } 104 | 105 | // ListCertificates Returns a list of all certificates for a tenant. 106 | func ListCertificates(cmd *cobra.Command, args []string) error { 107 | 108 | client, err := auth.GetClient() 109 | if err != nil { 110 | return err 111 | } 112 | 113 | // Silence Usage 114 | cmd.SilenceUsage = true 115 | 116 | resp, err := client.ForwardersService.ListCertificates() 117 | if err != nil { 118 | return err 119 | } 120 | jsonx.Pprint(cmd, resp) 121 | return nil 122 | } 123 | -------------------------------------------------------------------------------- /test/integration/provisioner_integration_test.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | "time" 7 | 8 | "github.com/splunk/splunk-cloud-sdk-go/services" 9 | "github.com/splunk/splunk-cloud-sdk-go/services/provisioner" 10 | testutils "github.com/splunk/splunk-cloud-sdk-go/test/utils" 11 | "github.com/splunk/splunk-cloud-sdk-go/util" 12 | "github.com/stretchr/testify/assert" 13 | "github.com/stretchr/testify/require" 14 | ) 15 | 16 | // TestInvite tests invitation functions in provisioner 17 | func TestInvite(t *testing.T) { 18 | config := &services.Config{ 19 | Token: testutils.TestAuthenticationToken, 20 | Host: testutils.TestSplunkCloudHost, 21 | Tenant: testutils.TestTenant, 22 | } 23 | client, err := services.NewClient(config) 24 | require.Emptyf(t, err, "error calling services.NewClient(config): %s", err) 25 | 26 | provClient := provisioner.NewService(client) 27 | tenant := testutils.TestTenant 28 | 29 | t.Run("pre: clean up invites", func(t *testing.T) { 30 | invites, err := provClient.ListInvites() 31 | require.Emptyf(t, err, "error cleaning up invites with provisioner.ListInvites(): %s", err) 32 | 33 | for _, i := range *invites { 34 | err = provClient.DeleteInvite(i.InviteID) 35 | assert.Emptyf(t, err, "error cleaning up invites with provisioner.DeleteInvite(): %s", err) 36 | } 37 | }) 38 | 39 | var invite *provisioner.InviteInfo 40 | var inviteID string 41 | 42 | t.Run("create invite", func(t *testing.T) { 43 | comment := "Go SDK test invite" 44 | email := "bounce@simulator.amazonses.com" 45 | var resp http.Response 46 | invite, err = provClient.CreateInvite(provisioner.InviteBody{ 47 | Email: email, 48 | Comment: &comment, 49 | Groups: []string{"group1", "group2"}, 50 | }, &resp) 51 | require.Emptyf(t, err, "error calling provisioner.CreateInvite(): %s", err) 52 | assert.Equal(t, tenant, invite.Tenant) 53 | assert.Equal(t, comment, invite.Comment) 54 | assert.Equal(t, email, invite.Email) 55 | assert.Equal(t, 2, len(invite.Groups)) 56 | }) 57 | 58 | time.Sleep(time.Second * 5) 59 | 60 | require.NotEmpty(t, invite, "invite test flow failed") 61 | 62 | t.Run("get invite", func(t *testing.T) { 63 | inviteID = invite.InviteID 64 | invite, err = provClient.GetInvite(inviteID) 65 | require.Emptyf(t, err, "error calling provisioner.GetInvite(): %s", err) 66 | assert.Equal(t, inviteID, invite.InviteID) 67 | assert.Equal(t, tenant, invite.Tenant) 68 | }) 69 | 70 | t.Run("list invites", func(t *testing.T) { 71 | invites, err := provClient.ListInvites() 72 | require.Emptyf(t, err, "error calling provisioner.ListInvites(): %s", err) 73 | found := false 74 | for _, i := range *invites { 75 | if i.InviteID == inviteID { 76 | found = true 77 | } 78 | } 79 | assert.True(t, found) 80 | }) 81 | 82 | t.Run("update invite", func(t *testing.T) { 83 | invite, err = provClient.UpdateInvite(inviteID, provisioner.UpdateInviteBody{ 84 | Action: provisioner.UpdateInviteBodyActionResend, 85 | }) 86 | assert.Equal(t, http.StatusLocked, err.(*util.HTTPError).HTTPStatusCode, "error calling provisioner.UpdateInvite(): %s", err) 87 | }) 88 | 89 | t.Run("delete invite", func(t *testing.T) { 90 | err = provClient.DeleteInvite(inviteID) 91 | assert.Emptyf(t, err, "error calling provisioner.DeleteInvite(): %s", err) 92 | }) 93 | } 94 | -------------------------------------------------------------------------------- /services/provisioner/model_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2022 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | * 16 | * Provisioner 17 | * 18 | * With the Provisioner service in Splunk Cloud Services, you can provision and manage tenants. 19 | * 20 | * API version: v1beta1.4 (recommended default) 21 | * Generated by: OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. 22 | */ 23 | 24 | package provisioner 25 | 26 | type Error struct { 27 | // Service error code 28 | Code string `json:"code"` 29 | // Human readable error message 30 | Message string `json:"message"` 31 | } 32 | 33 | type InviteBody struct { 34 | Email string `json:"email"` 35 | Comment *string `json:"comment,omitempty"` 36 | Groups []string `json:"groups,omitempty"` 37 | } 38 | 39 | type InviteInfo struct { 40 | Comment string `json:"comment"` 41 | CreatedAt string `json:"createdAt"` 42 | CreatedBy string `json:"createdBy"` 43 | Email string `json:"email"` 44 | Errors InviteInfoErrors `json:"errors"` 45 | ExpiresAt string `json:"expiresAt"` 46 | Groups []string `json:"groups"` 47 | InviteID string `json:"inviteID"` 48 | Status InviteInfoStatus `json:"status"` 49 | Tenant string `json:"tenant"` 50 | UpdatedAt string `json:"updatedAt"` 51 | UpdatedBy string `json:"updatedBy"` 52 | } 53 | 54 | type InviteInfoStatus string 55 | 56 | // List of InviteInfoStatus 57 | const ( 58 | InviteInfoStatusCreated InviteInfoStatus = "created" 59 | InviteInfoStatusInvited InviteInfoStatus = "invited" 60 | InviteInfoStatusAccepted InviteInfoStatus = "accepted" 61 | InviteInfoStatusRejected InviteInfoStatus = "rejected" 62 | InviteInfoStatusExpired InviteInfoStatus = "expired" 63 | InviteInfoStatusFailed InviteInfoStatus = "failed" 64 | InviteInfoStatusInvalid InviteInfoStatus = "invalid" 65 | ) 66 | 67 | type InviteInfoErrors []InviteInfoErrorsItems 68 | 69 | type InviteInfoErrorsItems struct { 70 | Action string `json:"action"` 71 | Code string `json:"code"` 72 | Message string `json:"message"` 73 | Group *string `json:"group,omitempty"` 74 | } 75 | 76 | type Invites []InviteInfo 77 | 78 | type TenantInfo struct { 79 | CreatedAt string `json:"createdAt"` 80 | CreatedBy string `json:"createdBy"` 81 | Name string `json:"name"` 82 | Status string `json:"status"` 83 | } 84 | 85 | type Tenants []TenantInfo 86 | 87 | type UpdateInviteBody struct { 88 | Action UpdateInviteBodyAction `json:"action"` 89 | } 90 | 91 | type UpdateInviteBodyAction string 92 | 93 | // List of UpdateInviteBodyAction 94 | const ( 95 | UpdateInviteBodyActionAccept UpdateInviteBodyAction = "accept" 96 | UpdateInviteBodyActionReject UpdateInviteBodyAction = "reject" 97 | UpdateInviteBodyActionResend UpdateInviteBodyAction = "resend" 98 | ) 99 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/collect_test.expected: -------------------------------------------------------------------------------- 1 | #testcase: collect create-execution --job-id 8b631454-c042-451e-80d7-2bb30bbc3ba2 2 | REQUEST URL:collect/v1beta1/jobs/8b631454-c042-451e-80d7-2bb30bbc3ba2/executions 3 | REQUEST BODY: 4 | 5 | #testcase: collect create-job --connector-ID aws-cloudwatch-metrics --name collector12 --parameters "{\"namespaces\": \"AWSEC2\"}" --schedule "16 * * * *" --scale-policy "{\"Static\": {\"Workers\":2}}" 6 | REQUEST URL:collect/v1beta1/jobs 7 | REQUEST BODY:{{"connectorID":"aws-cloudwatch-metrics","name":"collector12","parameters":{"namespaces":"AWSEC2"},"scalePolicy":{"static":{"workers":2}},"schedule":"16 * * * *"}} 8 | 9 | #testcase: collect delete-job --job-id 960173a2-3d21-4309-addb-0b2c2d43946e 10 | REQUEST URL:collect/v1beta1/jobs/960173a2-3d21-4309-addb-0b2c2d43946e 11 | REQUEST BODY: 12 | 13 | #testcase: collect delete-jobs 14 | REQUEST URL:collect/v1beta1/jobs 15 | REQUEST BODY: 16 | 17 | #testcase: collect get-execution --job-id 962b9053-5479-41bc-a5f6-e51f1c441496 --execution-uid 9a712d93-49b7-4c6d-9f1d-17df2a6d9249 18 | REQUEST URL:collect/v1beta1/jobs/962b9053-5479-41bc-a5f6-e51f1c441496/executions/9a712d93-49b7-4c6d-9f1d-17df2a6d9249 19 | REQUEST BODY: 20 | 21 | #testcase: collect get-job --job-id 960173a2-3d21-4309-addb-0b2c2d43946e 22 | REQUEST URL:collect/v1beta1/jobs/960173a2-3d21-4309-addb-0b2c2d43946e 23 | REQUEST BODY: 24 | 25 | #testcase: collect list-jobs --connector-id my-connector:v1.0.0dsfsdf 26 | REQUEST URL:collect/v1beta1/jobs?connectorID=my-connector%3Av1.0.0dsfsdf 27 | REQUEST BODY: 28 | 29 | #testcase: collect patch-execution --job-id 962b9053-5479-41bc-a5f6-e51f1c441496 --execution-uid 9a712d93-49b7-4c6d-9f1d-17df2a6d9249 --status canceled 30 | REQUEST URL:collect/v1beta1/jobs/962b9053-5479-41bc-a5f6-e51f1c441496/executions/9a712d93-49b7-4c6d-9f1d-17df2a6d9249 31 | REQUEST BODY:{{"status":"canceled"}} 32 | 33 | #testcase: collect patch-job --job-id e414f500-e165-44e4-a88e-d2dbdec569ca --name collector12 --parameters "{\"namespaces\": \"AWSEC2\"}" --schedule "17 * * * *" --scale-policy "{\"Static\": {\"Workers\":2}}" --scheduled false 34 | REQUEST URL:collect/v1beta1/jobs/e414f500-e165-44e4-a88e-d2dbdec569ca 35 | REQUEST BODY:{{"name":"collector12","parameters":{"namespaces":"AWSEC2"},"scalePolicy":{"static":{"workers":2}},"schedule":"17 * * * *","scheduled":false}} 36 | 37 | #testcase: collect patch-jobs --job-ids e414f500-e165-44e4-a88e-d2dbdec569ca --scale-policy "{\"Static\": {\"Workers\":2}}" 38 | REQUEST URL:collect/v1beta1/jobs?jobIDs=e414f500-e165-44e4-a88e-d2dbdec569ca 39 | REQUEST BODY:{{"scalePolicy":{"static":{"workers":2}}}} 40 | 41 | #testcase: collect patch-jobs --connector-id my-connector:v2.0.0 42 | REQUEST URL:collect/v1beta1/jobs?connectorID=my-connector%3Av2.0.0 43 | REQUEST BODY:{{}} 44 | 45 | #testcase: collect patch-jobs --connector-id my-connector:v2.0.0 --scale-policy "{\"Static\": {\"Workers\":2}}" 46 | REQUEST URL:collect/v1beta1/jobs?connectorID=my-connector%3Av2.0.0 47 | REQUEST BODY:{{"scalePolicy":{"static":{"workers":2}}}} 48 | 49 | #testcase: collect patch-jobs --job-ids "962b9053-5479-41bc-a5f6-e51f1c441496,004832bf-bbb8-4707-a9ff-5c2cfe4bf633" --event-extra-fields "[{\"name\": \"test\",\"value\":\"value1\"}]" 50 | REQUEST URL:collect/v1beta1/jobs?jobIDs=962b9053-5479-41bc-a5f6-e51f1c441496%2C004832bf-bbb8-4707-a9ff-5c2cfe4bf633 51 | REQUEST BODY:{{"eventExtraFields":[{"name":"test","value":"value1"}]}} 52 | 53 | -------------------------------------------------------------------------------- /examples/logging/logging.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | // This example demonstrates how to setup logging of requests/responses with the sdk using the standard Go "log" library. 18 | // 19 | // By default, this example logs to stout (for INFO level logs) and stderr (for ERROR level logs): 20 | // ```$ go run -v ./examples/logging/logging.go``` 21 | // 22 | // To log INFO and ERROR to a single log file use: 23 | // ```$ go run -v ./examples/logging/logging.go -logfile=``` 24 | package main 25 | 26 | import ( 27 | "flag" 28 | "fmt" 29 | "log" 30 | "os" 31 | 32 | "github.com/splunk/splunk-cloud-sdk-go/services" 33 | "github.com/splunk/splunk-cloud-sdk-go/services/identity" 34 | testutils "github.com/splunk/splunk-cloud-sdk-go/test/utils" 35 | "github.com/splunk/splunk-cloud-sdk-go/util" 36 | ) 37 | 38 | var logInfo *log.Logger 39 | var logErr *log.Logger 40 | 41 | func main() { 42 | // Setup logging to stdout and stderr by default 43 | logInfo, logErr = createStdLoggers() 44 | 45 | // If log file is specified, log there instead 46 | logFileArg := flag.String("logfile", "", "If non-empty, write log files in this file") 47 | flag.Parse() 48 | 49 | if logFileArg != nil && *logFileArg != "" { 50 | logFile, err := os.OpenFile(*logFileArg, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 51 | exitOnError(err) 52 | defer logFile.Close() 53 | logInfo, logErr = createFileLoggers(logFile) 54 | } 55 | 56 | // Get client 57 | logInfo.Print("Creating identity service client") 58 | 59 | config := &services.Config{ 60 | Token: testutils.TestAuthenticationToken, 61 | Host: testutils.TestSplunkCloudHost, 62 | Tenant: testutils.TestTenant, 63 | RoundTripper: util.NewSdkTransport(logInfo), 64 | } 65 | 66 | client, err := services.NewClient(config) 67 | exitOnError(err) 68 | 69 | serviceClient := identity.NewService(client) 70 | 71 | logInfo.Print("Validating token") 72 | input := identity.ValidateTokenQueryParams{Include: []identity.ValidateTokenincludeEnum{"principal", "tenant"}} 73 | 74 | info, err := serviceClient.ValidateToken(&input) 75 | exitOnError(err) 76 | logInfo.Print(fmt.Sprintf("Success! Info: %+v", info)) 77 | } 78 | 79 | func exitOnError(err error) { 80 | if err != nil { 81 | if logErr != nil { 82 | logErr.Print(err) 83 | } 84 | os.Exit(1) 85 | } 86 | } 87 | 88 | func createStdLoggers() (infoLogger *log.Logger, errLogger *log.Logger) { 89 | return log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile), 90 | log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) 91 | } 92 | 93 | func createFileLoggers(logFile *os.File) (infoLogger *log.Logger, errLogger *log.Logger) { 94 | return log.New(logFile, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile), 95 | log.New(logFile, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) 96 | } 97 | -------------------------------------------------------------------------------- /cmd/scloud/pkg/login/login.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "regexp" 7 | 8 | "github.com/spf13/cobra" 9 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/auth" 10 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/jsonx" 11 | ) 12 | 13 | const refreshFlow = "refresh" 14 | const pkceFlow = "pkce" 15 | const deviceFlow = "device" 16 | 17 | // TODO: Adding password handling 18 | type Options struct { 19 | verbose bool 20 | authKind string 21 | } 22 | 23 | // Login -- impl 24 | func Login(cmd *cobra.Command, args []string) error { 25 | 26 | // Step 1: Setup 27 | err := auth.LoginSetUp() 28 | if err != nil { 29 | return fmt.Errorf(`error login setup: ` + err.Error()) 30 | } 31 | 32 | // Step 2: Obtain LoginOptions 33 | loginOption, err := parseLoginOption(cmd) 34 | if err != nil { 35 | return fmt.Errorf(`error failed to parse command line: ` + err.Error()) 36 | } 37 | 38 | // Step 3: Get Authentication Flow function 39 | authFlow, err := auth.GetFlow(loginOption.authKind) 40 | if err != nil { 41 | return fmt.Errorf(`error authentication flow invalid: ` + err.Error()) 42 | } 43 | 44 | // Step 4: Login given authentication 45 | context, err := auth.Login(cmd, authFlow) 46 | if err != nil { 47 | if isHTTPError(err) { 48 | fmt.Printf("%v \n Try again using the --logtostderr flag to show details about the error.\n", err) 49 | return nil 50 | } 51 | return err 52 | } 53 | 54 | // Step 5: Print Context 55 | if loginOption.verbose { 56 | jsonx.Pprint(cmd, context) 57 | } 58 | 59 | return nil 60 | } 61 | 62 | // check whether the error contains 400s and 500s HTTP error 63 | func isHTTPError(err error) bool { 64 | regex := regexp.MustCompile(`(400|401|403|404|500|502|503|504){1}`) 65 | return regex.MatchString(err.Error()) 66 | } 67 | func getAuthKindFromProfile() (string, error) { 68 | profile, err := auth.GetEnvironmentProfile() 69 | 70 | if err != nil { 71 | return "", errors.New("error failed to obtain environment") 72 | } 73 | 74 | kind, ok := profile["kind"] 75 | if !ok { 76 | return "", errors.New("missing kind") 77 | } 78 | return kind, nil 79 | } 80 | 81 | func parseLoginOption(cmd *cobra.Command) (*Options, error) { 82 | verbose, err := cmd.Flags().GetBool("verbose") 83 | if err != nil { 84 | return nil, errors.New(`error parsing "verbose": ` + err.Error()) 85 | } 86 | 87 | isRefreshFlow, err := cmd.Flags().GetBool("use-refresh-token") 88 | if err != nil { 89 | return nil, errors.New(`error parsing "use-refresh-token": ` + err.Error()) 90 | } 91 | 92 | isPKCEFlow, err := cmd.Flags().GetBool("use-pkce") 93 | if err != nil { 94 | return nil, errors.New(`error parsing "use-pkce": ` + err.Error()) 95 | } 96 | 97 | isDeviceFlow, err := cmd.Flags().GetBool("use-device") 98 | if err != nil { 99 | return nil, errors.New(`error parsing "use-device": ` + err.Error()) 100 | } 101 | 102 | var authKind string 103 | 104 | if isRefreshFlow { 105 | authKind = refreshFlow 106 | } else if isPKCEFlow { 107 | authKind = pkceFlow 108 | } else if isDeviceFlow { 109 | authKind = deviceFlow 110 | } else { 111 | authKind, err = getAuthKindFromProfile() 112 | 113 | if err != nil { 114 | return nil, errors.New(`error obtaining authentication kind: ` + err.Error()) 115 | } 116 | } 117 | 118 | return &Options{ 119 | verbose: verbose, 120 | authKind: authKind, 121 | }, nil 122 | } 123 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/context/context.go: -------------------------------------------------------------------------------- 1 | package context 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/auth" 8 | "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/jsonx" 9 | usageUtil "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/util" 10 | "github.com/thoas/go-funk" 11 | ) 12 | 13 | const ExpiresIn = 43200 14 | const DefaultExpiresIn = 3600 15 | const TokenType = "Bearer" 16 | const Scope = "offline_access openid email profile" 17 | const DefaultEnv = "prod" 18 | 19 | var ValidKeys = map[string]interface{}{ 20 | "access_token": "", 21 | } 22 | 23 | func Cmd() *cobra.Command { 24 | return contextCmd 25 | } 26 | 27 | var contextCmd = &cobra.Command{ 28 | Use: "context", 29 | Short: "Token Context Information", 30 | Long: "Context represents an authentication context, which is the result of a successful OAuth authentication", 31 | Run: func(cmd *cobra.Command, args []string) { 32 | _ = cmd.Usage() 33 | }, 34 | } 35 | 36 | var list = &cobra.Command{ 37 | Use: "list", 38 | Short: "Display the token context details, including the access token and expiration", 39 | Run: func(cmd *cobra.Command, args []string) { 40 | tenant, _ := cmd.Flags().GetString("tenant") 41 | 42 | if tenant == "" { 43 | context := auth.GetAllContext(cmd) 44 | jsonx.Pprint(cmd, context) 45 | } else { 46 | context := auth.GetContext(cmd, tenant) 47 | jsonx.Pprint(cmd, context) 48 | } 49 | }, 50 | } 51 | 52 | var set = &cobra.Command{ 53 | Use: "set", 54 | Short: "Set token context details", 55 | Run: func(cmd *cobra.Command, args []string) { 56 | 57 | // Extract flag values 58 | key, _ := cmd.Flags().GetString("key") 59 | value, _ := cmd.Flags().GetString("value") 60 | tenant, _ := cmd.Flags().GetString("tenant") 61 | 62 | // Validate Key 63 | var isValidKey = funk.Contains(ValidKeys, key) 64 | 65 | if !isValidKey { 66 | message := fmt.Sprintf("Here are the keys you can set:\n %s\n", ValidKeys) 67 | jsonx.Pprint(cmd, message) 68 | return 69 | } 70 | 71 | expirationToUse := DefaultExpiresIn 72 | 73 | if auth.GetEnvironmentName() != DefaultEnv { 74 | expirationToUse = ExpiresIn 75 | } 76 | 77 | clientID, err := auth.GetClientID(cmd) 78 | if err != nil { 79 | jsonx.Pprint(cmd, err) 80 | return 81 | } 82 | 83 | currentContext := auth.GetCurrentContext(clientID, tenant) 84 | var context map[string]interface{} 85 | 86 | if currentContext == nil { 87 | context = map[string]interface{}{ 88 | "token_type": TokenType, 89 | "scope": Scope, 90 | } 91 | } else { 92 | context = auth.ToMap(currentContext) 93 | } 94 | 95 | context[key] = value 96 | context["expires_in"] = expirationToUse 97 | 98 | auth.SetContext(cmd, tenant, context) 99 | }, 100 | } 101 | 102 | func init() { 103 | contextCmd.AddCommand(list) 104 | contextCmd.AddCommand(set) 105 | 106 | set.Flags().StringP("key", "k", "", "The key stored in the context file") 107 | set.Flags().StringP("value", "p", "", "The value stored in the context file") 108 | set.Flags().StringP("tenant", "", "", "The tenant associated with the context") 109 | 110 | _ = set.MarkFlagRequired("tenant") 111 | _ = set.MarkFlagRequired("key") 112 | _ = set.MarkFlagRequired("value") 113 | 114 | list.LocalFlags().StringP("tenant", "", "", "Optional flag to list context for a given tenant") 115 | 116 | contextCmd.SetUsageTemplate(usageUtil.UsageTemplate) 117 | contextCmd.SetHelpTemplate(usageUtil.HelpTemplate) 118 | } 119 | -------------------------------------------------------------------------------- /services/provisioner/interface_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | // Code generated by gen_interface.go. DO NOT EDIT. 18 | 19 | package provisioner 20 | 21 | import ( 22 | "net/http" 23 | ) 24 | 25 | // ServicerGenerated represents the interface for implementing all endpoints for this service 26 | type ServicerGenerated interface { 27 | /* 28 | CreateInvite - provisioner service endpoint 29 | Creates an invitation for a person to join the tenant using their email address. 30 | Parameters: 31 | inviteBody 32 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 33 | */ 34 | CreateInvite(inviteBody InviteBody, resp ...*http.Response) (*InviteInfo, error) 35 | /* 36 | DeleteInvite - provisioner service endpoint 37 | Removes an invitation in the given tenant. 38 | Parameters: 39 | inviteId 40 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 41 | */ 42 | DeleteInvite(inviteId string, resp ...*http.Response) error 43 | /* 44 | GetInvite - provisioner service endpoint 45 | Returns an invitation in the given tenant. 46 | Parameters: 47 | inviteId 48 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 49 | */ 50 | GetInvite(inviteId string, resp ...*http.Response) (*InviteInfo, error) 51 | /* 52 | GetTenant - provisioner service endpoint 53 | Returns a specific tenant. 54 | Parameters: 55 | tenantName 56 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 57 | */ 58 | GetTenant(tenantName string, resp ...*http.Response) (*TenantInfo, error) 59 | /* 60 | ListInvites - provisioner service endpoint 61 | Returns a list of invitations in a given tenant. 62 | Parameters: 63 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 64 | */ 65 | ListInvites(resp ...*http.Response) (*Invites, error) 66 | /* 67 | ListTenants - provisioner service endpoint 68 | Returns all tenants that the user can read. 69 | Parameters: 70 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 71 | */ 72 | ListTenants(resp ...*http.Response) (*Tenants, error) 73 | /* 74 | UpdateInvite - provisioner service endpoint 75 | Modifies an invitation in the given tenant. 76 | Parameters: 77 | inviteId 78 | updateInviteBody 79 | resp: an optional pointer to a http.Response to be populated by this method. NOTE: only the first resp pointer will be used if multiple are provided 80 | */ 81 | UpdateInvite(inviteId string, updateInviteBody UpdateInviteBody, resp ...*http.Response) (*InviteInfo, error) 82 | } 83 | -------------------------------------------------------------------------------- /services/collect/param_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2021 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | * 16 | * Collect Service 17 | * 18 | * With the Collect service in Splunk Cloud Services, you can manage how data collection jobs ingest event and metric data. 19 | * 20 | * API version: v1beta1.8 (recommended default) 21 | * Generated by: OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. 22 | */ 23 | 24 | package collect 25 | 26 | // ListJobsQueryParams represents valid query parameters for the ListJobs operation 27 | // For convenience ListJobsQueryParams can be formed in a single statement, for example: 28 | // `v := ListJobsQueryParams{}.SetConnectorId(...)` 29 | type ListJobsQueryParams struct { 30 | // ConnectorId : Specifies the connector ID used to filter jobs. A tailing wildcard is supported for the connector ID tag. If no wildcard is used then an exact match is used. Examples: * `my-connector:v1.0.0` selects `my-connector` connector with an exact match with tag \"v1.0.0\" * `my-connector` selects `my-connector` connector with an exact match. Note as no tag is specified it actually refers to \"latest\". * `my-connector:v1.*` selects all `my-connector` connectors with tags starting with \"v1.\", e.g. \"v1.0\", \"v1.1.1\", \"v1.2-alpha\", etc. * `my-connector:*` selects all `my-connector` connectors with any tag. 31 | ConnectorId string `key:"connectorID"` 32 | } 33 | 34 | func (q ListJobsQueryParams) SetConnectorId(v string) ListJobsQueryParams { 35 | q.ConnectorId = v 36 | return q 37 | } 38 | 39 | // PatchJobsQueryParams represents valid query parameters for the PatchJobs operation 40 | // For convenience PatchJobsQueryParams can be formed in a single statement, for example: 41 | // `v := PatchJobsQueryParams{}.SetConnectorId(...).SetJobIDs(...)` 42 | type PatchJobsQueryParams struct { 43 | // ConnectorId : Specifies the connector ID used to filter jobs. A tailing wildcard is supported for the connector ID tag. If no wildcard is used then an exact match is used. Examples: * `my-connector:v1.0.0` selects `my-connector` connector with an exact match with tag \"v1.0.0\" * `my-connector` selects `my-connector` connector with an exact match. Note as no tag is specified it actually refers to \"latest\". * `my-connector:v1.*` selects all `my-connector` connectors with tags starting with \"v1.\", e.g. \"v1.0\", \"v1.1.1\", \"v1.2-alpha\", etc. * `my-connector:*` selects all `my-connector` connectors with any tag. 44 | ConnectorId string `key:"connectorID"` 45 | // JobIDs : The job ID list. 46 | JobIDs []string `key:"jobIDs" explode:"false"` 47 | } 48 | 49 | func (q PatchJobsQueryParams) SetConnectorId(v string) PatchJobsQueryParams { 50 | q.ConnectorId = v 51 | return q 52 | } 53 | 54 | func (q PatchJobsQueryParams) SetJobIDs(v []string) PatchJobsQueryParams { 55 | q.JobIDs = v 56 | return q 57 | } 58 | -------------------------------------------------------------------------------- /cmd/scloud/cmd/provisioner/provisioner-gen.go: -------------------------------------------------------------------------------- 1 | // Package provisioner -- generated by scloudgen 2 | // !! DO NOT EDIT !! 3 | // 4 | package provisioner 5 | 6 | import ( 7 | "github.com/spf13/cobra" 8 | impl "github.com/splunk/splunk-cloud-sdk-go/cmd/scloud/pkg/provisioner" 9 | ) 10 | 11 | // createInvite -- Creates an invitation for a person to join the tenant using their email address. 12 | var createInviteCmd = &cobra.Command{ 13 | Use: "create-invite", 14 | Short: "Creates an invitation for a person to join the tenant using their email address.", 15 | RunE: impl.CreateInvite, 16 | } 17 | 18 | // deleteInvite -- Removes an invitation in the given tenant. 19 | var deleteInviteCmd = &cobra.Command{ 20 | Use: "delete-invite", 21 | Short: "Removes an invitation in the given tenant.", 22 | RunE: impl.DeleteInvite, 23 | } 24 | 25 | // getInvite -- Returns an invitation in the given tenant. 26 | var getInviteCmd = &cobra.Command{ 27 | Use: "get-invite", 28 | Short: "Returns an invitation in the given tenant.", 29 | RunE: impl.GetInvite, 30 | } 31 | 32 | // getTenant -- Returns a specific tenant. 33 | var getTenantCmd = &cobra.Command{ 34 | Use: "get-tenant", 35 | Short: "Returns a specific tenant.", 36 | RunE: impl.GetTenant, 37 | } 38 | 39 | // listInvites -- Returns a list of invitations in a given tenant. 40 | var listInvitesCmd = &cobra.Command{ 41 | Use: "list-invites", 42 | Short: "Returns a list of invitations in a given tenant.", 43 | RunE: impl.ListInvites, 44 | } 45 | 46 | // listTenants -- Returns all tenants that the user can read. 47 | var listTenantsCmd = &cobra.Command{ 48 | Use: "list-tenants", 49 | Short: "Returns all tenants that the user can read.", 50 | RunE: impl.ListTenants, 51 | } 52 | 53 | // updateInvite -- Modifies an invitation in the given tenant. 54 | var updateInviteCmd = &cobra.Command{ 55 | Use: "update-invite", 56 | Short: "Modifies an invitation in the given tenant.", 57 | RunE: impl.UpdateInvite, 58 | } 59 | 60 | func init() { 61 | provisionerCmd.AddCommand(createInviteCmd) 62 | 63 | var createInviteEmail string 64 | createInviteCmd.Flags().StringVar(&createInviteEmail, "email", "", "This is a required parameter. ") 65 | createInviteCmd.MarkFlagRequired("email") 66 | 67 | var createInviteComment string 68 | createInviteCmd.Flags().StringVar(&createInviteComment, "comment", "", "") 69 | 70 | var createInviteGroups []string 71 | createInviteCmd.Flags().StringSliceVar(&createInviteGroups, "groups", nil, "") 72 | 73 | provisionerCmd.AddCommand(deleteInviteCmd) 74 | 75 | var deleteInviteInviteId string 76 | deleteInviteCmd.Flags().StringVar(&deleteInviteInviteId, "invite-id", "", "This is a required parameter. ") 77 | deleteInviteCmd.MarkFlagRequired("invite-id") 78 | 79 | provisionerCmd.AddCommand(getInviteCmd) 80 | 81 | var getInviteInviteId string 82 | getInviteCmd.Flags().StringVar(&getInviteInviteId, "invite-id", "", "This is a required parameter. ") 83 | getInviteCmd.MarkFlagRequired("invite-id") 84 | 85 | provisionerCmd.AddCommand(getTenantCmd) 86 | 87 | var getTenantTenantName string 88 | getTenantCmd.Flags().StringVar(&getTenantTenantName, "tenant-name", "", "This is a required parameter. ") 89 | getTenantCmd.MarkFlagRequired("tenant-name") 90 | 91 | provisionerCmd.AddCommand(listInvitesCmd) 92 | 93 | provisionerCmd.AddCommand(listTenantsCmd) 94 | 95 | provisionerCmd.AddCommand(updateInviteCmd) 96 | 97 | var updateInviteAction string 98 | updateInviteCmd.Flags().StringVar(&updateInviteAction, "action", "", "This is a required parameter. can accept values accept, reject, resend") 99 | updateInviteCmd.MarkFlagRequired("action") 100 | 101 | var updateInviteInviteId string 102 | updateInviteCmd.Flags().StringVar(&updateInviteInviteId, "invite-id", "", "This is a required parameter. ") 103 | updateInviteCmd.MarkFlagRequired("invite-id") 104 | 105 | } 106 | -------------------------------------------------------------------------------- /sdk/sdk.go: -------------------------------------------------------------------------------- 1 | package sdk 2 | 3 | import ( 4 | "github.com/splunk/splunk-cloud-sdk-go/services" 5 | "github.com/splunk/splunk-cloud-sdk-go/services/action" 6 | "github.com/splunk/splunk-cloud-sdk-go/services/appregistry" 7 | "github.com/splunk/splunk-cloud-sdk-go/services/catalog" 8 | "github.com/splunk/splunk-cloud-sdk-go/services/collect" 9 | "github.com/splunk/splunk-cloud-sdk-go/services/forwarders" 10 | "github.com/splunk/splunk-cloud-sdk-go/services/identity" 11 | "github.com/splunk/splunk-cloud-sdk-go/services/ingest" 12 | "github.com/splunk/splunk-cloud-sdk-go/services/kvstore" 13 | "github.com/splunk/splunk-cloud-sdk-go/services/ml" 14 | "github.com/splunk/splunk-cloud-sdk-go/services/provisioner" 15 | "github.com/splunk/splunk-cloud-sdk-go/services/search" 16 | "github.com/splunk/splunk-cloud-sdk-go/services/streams" 17 | ) 18 | 19 | // Client to communicate with Splunk Cloud service endpoints 20 | type Client struct { 21 | *services.BaseClient 22 | // ActionService talks to Splunk Cloud action service 23 | ActionService *action.Service 24 | // CatalogService talks to the Splunk Cloud catalog service 25 | CatalogService *catalog.Service 26 | // CollectService talks to the Splunk Cloud collect service 27 | CollectService *collect.Service 28 | // IdentityService talks to Splunk Cloud IAC service 29 | IdentityService *identity.Service 30 | // IngestService talks to the Splunk Cloud ingest service 31 | IngestService *ingest.Service 32 | // KVStoreService talks to Splunk Cloud kvstore service 33 | KVStoreService *kvstore.Service 34 | // SearchService talks to the Splunk Cloud search service 35 | SearchService *search.Service 36 | // StreamsService talks to the Splunk Cloud streams service 37 | StreamsService *streams.Service 38 | // ForwardersService talks to the Splunk Cloud forwarders service 39 | ForwardersService *forwarders.Service 40 | // appRegistryService talks to the Splunk Cloud app registry service 41 | AppRegistryService *appregistry.Service 42 | // MachineLearningService talks to the Splunk Cloud machine learning service 43 | MachineLearningService *ml.Service 44 | // ProvisionerService talks to the Splunk Cloud provisioner service 45 | ProvisionerService *provisioner.Service 46 | } 47 | 48 | // NewClient returns a Splunk Cloud client for communicating with any service 49 | func NewClient(config *services.Config) (*Client, error) { 50 | client, err := services.NewClient(config) 51 | if err != nil { 52 | return nil, err 53 | } 54 | return &Client{ 55 | BaseClient: client, 56 | ActionService: &action.Service{Client: client}, 57 | CatalogService: &catalog.Service{Client: client}, 58 | CollectService: &collect.Service{Client: client}, 59 | IdentityService: &identity.Service{Client: client}, 60 | IngestService: &ingest.Service{Client: client}, 61 | KVStoreService: &kvstore.Service{Client: client}, 62 | SearchService: &search.Service{Client: client}, 63 | StreamsService: &streams.Service{Client: client}, 64 | ForwardersService: &forwarders.Service{Client: client}, 65 | AppRegistryService: &appregistry.Service{Client: client}, 66 | MachineLearningService: &ml.Service{Client: client}, 67 | ProvisionerService: &provisioner.Service{Client: client}, 68 | }, nil 69 | } 70 | 71 | // NewBatchEventsSenderWithMaxAllowedError is Deprecated: please use client.IngestService.NewBatchEventsSenderWithMaxAllowedError 72 | func (c *Client) NewBatchEventsSenderWithMaxAllowedError(batchSize int, interval int64, maxErrorsAllowed int) (*ingest.BatchEventsSender, error) { 73 | return c.IngestService.NewBatchEventsSenderWithMaxAllowedError(batchSize, interval, 0, maxErrorsAllowed) 74 | } 75 | 76 | // NewBatchEventsSender is Deprecated: please use client.IngestService.NewBatchEventsSender 77 | func (c *Client) NewBatchEventsSender(batchSize int, interval int64) (*ingest.BatchEventsSender, error) { 78 | return c.IngestService.NewBatchEventsSender(batchSize, interval, 0) 79 | } 80 | -------------------------------------------------------------------------------- /cmd/scloud/test/testcases/test_stream_create_template.json: -------------------------------------------------------------------------------- 1 | { 2 | "edges": [ 3 | { 4 | "sourceNode": "2c5aa0e6-ccc5-3577-9f12-5d8c466c4e84", 5 | "sourcePort": "output", 6 | "targetNode": "ba342517-84db-302e-8fb7-545b49752cc3", 7 | "targetPort": "input" 8 | }, 9 | { 10 | "sourceNode": "ba342517-84db-302e-8fb7-545b49752cc3", 11 | "sourcePort": "output", 12 | "targetNode": "8a9a491b-ed6d-3ced-8ad5-9eb966d3c226", 13 | "targetPort": "input" 14 | }, 15 | { 16 | "sourceNode": "8a9a491b-ed6d-3ced-8ad5-9eb966d3c226", 17 | "sourcePort": "output", 18 | "targetNode": "2c43f86e-ad69-3ce1-8fdb-8f1b59ba5370", 19 | "targetPort": "input" 20 | }, 21 | { 22 | "sourceNode": "2c43f86e-ad69-3ce1-8fdb-8f1b59ba5370", 23 | "sourcePort": "output", 24 | "targetNode": "3ab66bd5-c6f4-3192-9123-54467d7feabf", 25 | "targetPort": "input" 26 | } 27 | ], 28 | "nodes": [ 29 | { 30 | "id": "2c5aa0e6-ccc5-3577-9f12-5d8c466c4e84", 31 | "op": "from_generate_events", 32 | "arguments": { 33 | "interval": 1000, 34 | "type": "timestamp" 35 | }, 36 | "attributes": { 37 | "user": { 38 | "name": "Generate Events: Generate Sample Data", 39 | "notes": "" 40 | } 41 | }, 42 | "resolvedId": "from_generate_events:string:long" 43 | }, 44 | { 45 | "id": "ba342517-84db-302e-8fb7-545b49752cc3", 46 | "op": "eval", 47 | "arguments": { 48 | "function": [ 49 | "body=concat(\"0XGFSod1vIoyZeTdldL2vR4wbWZFRTo25,qVbCl1Yn2XYhp7wQVzBE0ik7kI2pAsUI,Credit Card,1615.65,\", strftime(now()-5000, \"%Y-%m-%d %H:%M:%S\", null), \",\", strftime(now(), \"%Y-%m-%d %H:%M:%S\", null), \",-73.953948,40.771702,2475601523770875\")" 50 | ] 51 | }, 52 | "attributes": { 53 | "user": { 54 | "name": "Eval: Format Sample Events", 55 | "notes": "" 56 | } 57 | }, 58 | "resolvedId": "eval:collection>:collection>" 59 | }, 60 | { 61 | "id": "8a9a491b-ed6d-3ced-8ad5-9eb966d3c226", 62 | "op": "eval", 63 | "arguments": { 64 | "function": [ 65 | "body=extract_regex(body, /(?[^,]+),(?[^,]+),(?[^,]+),(?[^,]+),(?\\S+)\\s(?\\S+),(?\\S+)\\s(?\\S+?),(?\\S+?),(?\\S+?),(?\\d*)/)", 66 | "body=map_set(body, \"Card\", \"\")", 67 | "source_type=\"cc_transactions:json\"", 68 | "timestamp=strptime(concat(body.sdate, \" \", body.stime), \"%Y-%m-%d %H:%M:%S\", \"UTC\")" 69 | ] 70 | }, 71 | "attributes": { 72 | "user": { 73 | "name": "Eval: Redact Credit Card Numbers", 74 | "notes": "" 75 | } 76 | }, 77 | "resolvedId": "eval:collection>:collection>" 78 | }, 79 | { 80 | "id": "2c43f86e-ad69-3ce1-8fdb-8f1b59ba5370", 81 | "op": "fields", 82 | "arguments": { 83 | "field_list": [ 84 | "timestamp", 85 | "body", 86 | "source_type" 87 | ], 88 | "operator": "+" 89 | }, 90 | "attributes": { 91 | "user": { 92 | "name": "Fields: Keep Specific Fields", 93 | "notes": "" 94 | } 95 | }, 96 | "resolvedId": "fields:collection>:collection" 97 | }, 98 | { 99 | "id": "3ab66bd5-c6f4-3192-9123-54467d7feabf", 100 | "op": "into_dev_null", 101 | "attributes": { 102 | "user": { 103 | "name": "Send to Null: Placeholder for Destination", 104 | "notes": "" 105 | } 106 | }, 107 | "resolvedId": "into_dev_null:collection>" 108 | } 109 | ], 110 | "attributes": { 111 | "activeNodeId": "2c5aa0e6-ccc5-3577-9f12-5d8c466c4e84" 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /services/search/iterator.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package search 18 | 19 | import ( 20 | "errors" 21 | ) 22 | 23 | // QueryFunc is the function to be executed in each Next call of the iterator 24 | type QueryFunc func(step, start int) (*ListSearchResultsResponse, error) 25 | 26 | // Iterator is the result of a search query. Its cursor starts at 0 index 27 | // of the result set. Use Next() to advance through the rows: 28 | // 29 | // search, _ := client.SearchService.SubmitSearch(&PostJobsRequest{Search: "search index=main | head 5"}) 30 | // pages, _ := search.QueryResults(2, 0, &FetchResultsRequest{Count: 5}) 31 | // defer pages.Close() 32 | // for pages.Next() { 33 | // values, err := pages.Value() 34 | // ... 35 | // 36 | // } 37 | // err := pages.Err() // get any error encountered during iteration 38 | // ... 39 | type Iterator struct { 40 | value *ListSearchResultsResponse // stores current value 41 | max int // max number of results 42 | start int // index to start with fetching results, same concept as "offset" 43 | offset int // offset value to start iterator with. e.g. offset=5 means iterator will skip the first 5 results 44 | batch int // batch size of results in each Next call 45 | err error // error encountered during iteration 46 | fn QueryFunc // function to be executed in each Next call 47 | isClosed bool // signal indicating status of the iterator 48 | } 49 | 50 | // NewIterator creates a new reference to the iterator object 51 | func NewIterator(batch, offset, max int, fn QueryFunc) *Iterator { 52 | return &Iterator{ 53 | start: offset, 54 | batch: batch, 55 | max: max, 56 | fn: fn, 57 | isClosed: false, 58 | offset: offset, 59 | } 60 | } 61 | 62 | // Value returns value in current iteration or error out if iterator is closed 63 | func (i *Iterator) Value() (*ListSearchResultsResponse, error) { 64 | if i.isClosed == true { 65 | return nil, errors.New("failed to retrieve values on a closed iterator") 66 | } 67 | return i.value, nil 68 | } 69 | 70 | // Next prepares the next result set for reading with the Value method. It 71 | // returns true on success, or false if there is no next result row or an error 72 | // occurred while preparing it. 73 | // 74 | // Every call to Value, even the first one, must be preceded by a call to Next. 75 | func (i *Iterator) Next() bool { 76 | if i.start > i.max || i.isClosed == true || i.err != nil { 77 | return false 78 | } 79 | results, err := i.fn(i.batch, i.start) 80 | if err != nil { 81 | i.err = err 82 | return false 83 | } 84 | // No more results 85 | if len(results.Results) == 0 { 86 | return false 87 | } 88 | i.value = results 89 | // Return all results, therefore no longer need to iterate 90 | if i.batch == 0 { 91 | return false 92 | } 93 | i.start += i.batch 94 | return true 95 | } 96 | 97 | // Close checks the status and closes iterator if it's not already. After Close, no results can be retrieved 98 | func (i *Iterator) Close() { 99 | if i.isClosed != true { 100 | i.isClosed = true 101 | } 102 | } 103 | 104 | // Err returns error encountered during iteration 105 | func (i *Iterator) Err() error { 106 | return i.err 107 | } 108 | -------------------------------------------------------------------------------- /examples/mock/mock.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | // This example demonstrates how to setup the Splunk Cloud SDK for Go to return mocked 18 | // responses rather than sending requests to the Splunk Cloud Platform itself. 19 | // 20 | // Invoke this example using ```$ go run -v ./examples/mock/mock.go``` 21 | package main 22 | 23 | import ( 24 | "bytes" 25 | "encoding/json" 26 | "fmt" 27 | "io/ioutil" 28 | "net/http" 29 | "os" 30 | 31 | "github.com/splunk/splunk-cloud-sdk-go/sdk" 32 | "github.com/splunk/splunk-cloud-sdk-go/services" 33 | "github.com/splunk/splunk-cloud-sdk-go/services/identity" 34 | "github.com/splunk/splunk-cloud-sdk-go/services/search" 35 | "github.com/splunk/splunk-cloud-sdk-go/util" 36 | ) 37 | 38 | func main() { 39 | client, err := sdk.NewClient(&services.Config{ 40 | Tenant: "foo", 41 | Token: "faked.token", 42 | RoundTripper: mockTransport{}, 43 | }) 44 | exitOnError(err) 45 | var resp http.Response 46 | fmt.Println("Sending request to mocked IdentityService.ValidateToken() endpoint ...") 47 | info, err := client.IdentityService.ValidateToken(nil, &resp) 48 | // MOCKING [/foo/identity/v2beta1/validate] 49 | exitOnError(err) 50 | fmt.Printf("%-10s[%d] %+v\n\n", "RESPONSE", resp.StatusCode, info) 51 | // RESPONSE [200] &{ClientId: Name:someone@domain.com Principal: Tenant:} 52 | fmt.Println("Sending request to unmocked SearchService.CreateJob() endpoint ...") 53 | job := search.SearchJob{Query: "| from index:main | head 5"} 54 | _, err = client.SearchService.CreateJob(job, &resp) 55 | // MOCKING [/foo/search/v2beta1/jobs] 56 | // Expecting an err this time 57 | if httpErr, ok := err.(*util.HTTPError); ok { 58 | fmt.Printf("%-10s[%d] %+v\n\n", "RESPONSE", resp.StatusCode, httpErr) 59 | // RESPONSE [404] {"HTTPStatusCode":404,"HTTPStatus":"Not Found","message":"endpoint not found","code":"route_not_found"} 60 | fmt.Printf("Success.") 61 | os.Exit(0) 62 | } 63 | exitOnError(fmt.Errorf("expected to receive a 404 error but none was returned")) 64 | } 65 | 66 | func exitOnError(err error) { 67 | if err != nil { 68 | fmt.Println(err.Error()) 69 | os.Exit(1) 70 | } 71 | } 72 | 73 | // mockTransport defines a RoundTripper to be added to our services.Config 74 | // which intercepts requests from the client and returns its own mocked 75 | // responses 76 | type mockTransport struct{} 77 | 78 | // RoundTrip is the method needed to implement the http.RoundTripper interface. 79 | // This is where mocks for various endpoints are implemented. 80 | func (m mockTransport) RoundTrip(request *http.Request) (*http.Response, error) { 81 | resp := &http.Response{} 82 | fmt.Printf("%-10s[%s]\n", "MOCKING", request.URL.EscapedPath()) 83 | switch request.URL.EscapedPath() { 84 | // Define our mocked responses here, for request URLs that we haven't 85 | // mocked, return a 404 (http.StatusNotFound) response 86 | case "/foo/identity/v3/validate": 87 | info := identity.ValidateInfo{ 88 | Name: "someone@domain.com", 89 | } 90 | b, _ := json.Marshal(&info) 91 | // Return a 200 with our ValidateInfo model contents defined above 92 | resp.StatusCode = http.StatusOK 93 | resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) 94 | return resp, nil 95 | default: 96 | resp.StatusCode = http.StatusNotFound 97 | resp.Status = "Not Found" 98 | resp.Body = ioutil.NopCloser(bytes.NewBufferString(`{"code":"route_not_found", "message":"endpoint not found"}`)) 99 | return resp, nil 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /test/utils/utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package utils 18 | 19 | import ( 20 | "fmt" 21 | "log" 22 | "os" 23 | "path/filepath" 24 | "runtime" 25 | "time" 26 | 27 | "github.com/joho/godotenv" 28 | "github.com/splunk/splunk-cloud-sdk-go/idp" 29 | "github.com/splunk/splunk-cloud-sdk-go/sdk" 30 | "github.com/splunk/splunk-cloud-sdk-go/services" 31 | ) 32 | 33 | // GetFilename uses reflection to get current filename 34 | func GetFilename() string { 35 | _, filename, _, _ := runtime.Caller(0) 36 | return filename 37 | } 38 | 39 | func init() { 40 | envPath := filepath.Join(filepath.Dir(GetFilename()), "..", "..", ".env") 41 | 42 | err := godotenv.Load(envPath) 43 | 44 | if err != nil { 45 | log.Println("Error loading .env from ", envPath) 46 | } 47 | 48 | TestAuthenticationToken = os.Getenv("BEARER_TOKEN") 49 | TestSplunkCloudHost = os.Getenv("SPLUNK_CLOUD_HOST_TENANT_SCOPED") 50 | 51 | TestTenant = os.Getenv("TEST_TENANT_SCOPED") 52 | 53 | TestRegion = os.Getenv("REGION") 54 | 55 | TestUsername = os.Getenv("BACKEND_CLIENT_ID_TENANT_SCOPED") 56 | ExpiredAuthenticationToken = os.Getenv("EXPIRED_BEARER_TOKEN") 57 | PkceClientID = os.Getenv("REFRESH_TOKEN_CLIENT_ID") 58 | Username = os.Getenv("TEST_USERNAME") 59 | Password = os.Getenv("TEST_PASSWORD") 60 | IdpHost = os.Getenv("IDP_HOST_TENANT_SCOPED") 61 | } 62 | 63 | // RunSuffix - run instance identifier suffix based on timestamp 64 | var RunSuffix = time.Now().Unix() 65 | 66 | // TestSplunkCloudHost - the url for the test api to be used 67 | var TestSplunkCloudHost string 68 | 69 | // TestAuthenticationToken - the authentication that gives permission to make requests against the api 70 | var TestAuthenticationToken string 71 | 72 | // TestTenant - the tenant to be used for the API 73 | var TestTenant string 74 | 75 | // TestUsername - the user running tests on behalf of 76 | var TestUsername string 77 | 78 | // TestInvalidTestTenant - the invalid tenant ID that denies permission to make requests against the api 79 | var TestInvalidTestTenant = "INVALID_TENANT_ID" 80 | 81 | // ExpiredAuthenticationToken - to test authentication retries 82 | var ExpiredAuthenticationToken string 83 | 84 | // TestModule - A namespace for integration testing 85 | var TestModule = fmt.Sprintf("gomod%d", RunSuffix) 86 | 87 | // TestModule 2- A namespace for integration testing 88 | var TestModule2 = fmt.Sprintf("gomod2%d", RunSuffix) 89 | 90 | // TestCollection - A collection for integration testing 91 | var TestCollection = fmt.Sprintf("gocollection%d", RunSuffix) 92 | 93 | // StubbyTestCollection - A collection for stubby testing 94 | var StubbyTestCollection = "testcollection0" 95 | 96 | // TestTimeOut - the timeout to be used for requests to the api 97 | var TestTimeOut = time.Second * 30 98 | 99 | // TestTimeOut - the timeout to be used for requests to the api in search tests 100 | var LongTestTimeout = time.Second * 600 101 | 102 | //Region which correlates to the tenant, used to formulate tenant scoped hostnames 103 | var TestRegion string 104 | 105 | // PKCE 106 | const NativeAppRedirectURI = "https://login.splunkbeta.com" 107 | 108 | var PkceClientID string 109 | var Username string 110 | var Password string 111 | var IdpHost string 112 | 113 | // Get an client without the testing interface 114 | func MakeSdkClient(tr idp.TokenRetriever, tenant string) (*sdk.Client, error) { 115 | return sdk.NewClient(&services.Config{ 116 | TokenRetriever: tr, 117 | Host: TestSplunkCloudHost, 118 | Tenant: tenant, 119 | Timeout: TestTimeOut, 120 | }) 121 | } 122 | -------------------------------------------------------------------------------- /idp/idp_unit_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Splunk, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"): you may 5 | * not use this file except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | package idp 18 | 19 | import ( 20 | "bytes" 21 | "io" 22 | "net/http" 23 | "testing" 24 | 25 | "fmt" 26 | 27 | "github.com/stretchr/testify/assert" 28 | "github.com/stretchr/testify/require" 29 | ) 30 | 31 | func TestNewClient(t *testing.T) { 32 | const providerHost = "https://myhost.net/" 33 | hostURL := HostURLConfig{} 34 | client := NewClient(providerHost, "", "custom/authn", "custom/authz", "custom/token", "custom/system/token", "custom/csrfToken", "custom/system/device", false, hostURL) 35 | assert.Equal(t, client.ProviderHost, providerHost) 36 | assert.Equal(t, client.AuthnPath, "custom/authn") 37 | assert.Equal(t, client.AuthorizePath, "custom/authz") 38 | assert.Equal(t, client.TokenPath, "custom/token") 39 | assert.Equal(t, client.TenantTokenPath, "custom/system/token") 40 | assert.Equal(t, client.DevicePath, "custom/system/device") 41 | assert.Equal(t, client.CsrfTokenPath, "custom/csrfToken") 42 | clientEmptyParams := NewClient(providerHost, "", "", "", "", "", "", "", false, hostURL) 43 | assert.Equal(t, clientEmptyParams.ProviderHost, providerHost) 44 | assert.Equal(t, clientEmptyParams.AuthnPath, defaultAuthnPath) 45 | assert.Equal(t, clientEmptyParams.AuthorizePath, defaultAuthorizePath) 46 | assert.Equal(t, clientEmptyParams.TokenPath, defaultTokenPath) 47 | assert.Equal(t, clientEmptyParams.TenantTokenPath, defaultTenantTokenPath) 48 | assert.Equal(t, clientEmptyParams.DevicePath, defaultDevicePath) 49 | assert.Equal(t, clientEmptyParams.CsrfTokenPath, defaultCsrfTokenPath) 50 | } 51 | 52 | // This is required to use bytes.Buffer in the http.Request.Body 53 | type nopCloser struct { 54 | io.Reader 55 | } 56 | 57 | func (nopCloser) Close() error { return nil } 58 | 59 | func TestDecode(t *testing.T) { 60 | data := []byte(`{ 61 | "token_type":"Bearer", 62 | "access_token":"my.access.token", 63 | "expires_in":3600, 64 | "scope":"offline_access", 65 | "id_token":"my.id.token", 66 | "refresh_token":"my.refresh.token" 67 | }`) 68 | resp := http.Response{ 69 | StatusCode: 200, 70 | Body: nopCloser{bytes.NewBuffer(data)}, 71 | } 72 | ctx, err := decode(&resp) 73 | require.NotNil(t, ctx) 74 | require.NoError(t, err) 75 | assert.Equal(t, ctx.TokenType, "Bearer") 76 | assert.Equal(t, ctx.AccessToken, "my.access.token") 77 | assert.Equal(t, ctx.ExpiresIn, 3600) 78 | assert.Equal(t, ctx.Scope, "offline_access") 79 | assert.Equal(t, ctx.IDToken, "my.id.token") 80 | assert.Equal(t, ctx.RefreshToken, "my.refresh.token") 81 | assert.True(t, ctx.StartTime > 0) 82 | } 83 | 84 | func TestGetTenantScopedHost(t *testing.T) { 85 | tenant := "test-tenant" 86 | hostURL := "https://testauth.mycompany.com" 87 | hostName := "testauth.mycompany.com" 88 | 89 | hostURL, err := getTenantScopedHost(true, tenant, hostURL) 90 | require.NoError(t, err) 91 | expectedURL := fmt.Sprintf("https://%s.%s/", tenant, hostName) 92 | fmt.Println("Actual URL") 93 | fmt.Println(hostURL) 94 | fmt.Println("Expected URL") 95 | fmt.Println(expectedURL) 96 | require.Equal(t, hostURL, expectedURL) 97 | } 98 | 99 | func TestGetRegionScopedHost(t *testing.T) { 100 | hostURL := "https://testauth.mycompany.com" 101 | hostName := "testauth.mycompany.com" 102 | tokenPath := "csrfToken" 103 | region := "reg10" 104 | 105 | hostURL, err := getRegionScopedHost(true, region, hostURL) 106 | require.NoError(t, err) 107 | expectedURL := fmt.Sprintf("https://region-%s.%s/%s", region, hostName, tokenPath) 108 | fmt.Println("Actual URL") 109 | fmt.Println(hostURL) 110 | fmt.Println("Expected URL") 111 | fmt.Println(expectedURL) 112 | require.Equal(t, hostURL+tokenPath, expectedURL) 113 | } 114 | -------------------------------------------------------------------------------- /util/gen_interface.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "flag" 8 | "fmt" 9 | "os" 10 | "os/exec" 11 | "path/filepath" 12 | "strings" 13 | ) 14 | 15 | type filesFlag []string 16 | 17 | func (i *filesFlag) String() string { 18 | return "service file(s) containing struct" 19 | } 20 | 21 | func (i *filesFlag) Set(value string) error { 22 | *i = append(*i, value) 23 | return nil 24 | } 25 | 26 | var options struct { 27 | service string 28 | serviceFiles filesFlag 29 | structName string 30 | iface string 31 | icomment string 32 | pkgName string 33 | outputFile string 34 | comment string 35 | } 36 | 37 | // Prints an error message and exits. 38 | func fatal(msg string, args ...interface{}) { 39 | msg = fmt.Sprintf(msg, args...) 40 | fmt.Fprintf(os.Stderr, "error: %s\n", msg) 41 | os.Exit(1) 42 | } 43 | 44 | // Set up flags 45 | func init() { 46 | flag.StringVar(&options.service, "svc", "", "service name") 47 | flag.Var(&options.serviceFiles, "sf", "service file(s) containing struct") 48 | flag.StringVar(&options.structName, "s", "Service", "struct to generate interface from") 49 | flag.StringVar(&options.iface, "i", "Servicer", "name of generated interface") 50 | flag.StringVar(&options.icomment, "ic", "Servicer represents the interface for implementing all endpoints for this service", "name of generated interface") 51 | flag.StringVar(&options.pkgName, "p", "", "package name of generated interface") 52 | flag.StringVar(&options.outputFile, "o", "", "output file name. Print to stdout if not provided") 53 | flag.Parse() 54 | } 55 | 56 | func main() { 57 | var err error 58 | outFile := filepath.Join(options.service, "interface.go") 59 | args := []string{} 60 | for _, v := range options.serviceFiles { 61 | file := filepath.Join(options.service, v) 62 | fmt.Printf("generating from %s\n", file) 63 | args = append(args, "-f", file) 64 | } 65 | args = append(args, "-s", options.structName, "-i", options.iface, "-p", options.pkgName, "--iface-comment", options.icomment, "-c", "Code generated by gen_interface.go. DO NOT EDIT.", "-o", outFile) 66 | cmd := exec.Command("ifacemaker", args...) 67 | _, err = cmd.Output() 68 | if err != nil { 69 | fatal("%v", err) 70 | } 71 | 72 | for _, v := range options.serviceFiles { 73 | if strings.Contains(v, "service_generated.go") { 74 | file := filepath.Join(options.service, "interface.go") 75 | fmt.Printf("adding license to %s\n", file) 76 | err := addLicense(file) 77 | 78 | if err != nil { 79 | os.Exit(1) 80 | } 81 | } 82 | } 83 | } 84 | 85 | func addLicense(filepath string) error { 86 | licensetxt := []string{ 87 | "/*", 88 | " * Copyright © 2019 Splunk, Inc.", 89 | " *", 90 | " * Licensed under the Apache License, Version 2.0 (the \"License\"): you may", 91 | " * not use this file except in compliance with the License. You may obtain", 92 | " * a copy of the License at", 93 | " *", 94 | " * http://www.apache.org/licenses/LICENSE-2.0", 95 | " *", 96 | " * Unless required by applicable law or agreed to in writing, software", 97 | " * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT", 98 | " * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the", 99 | " * License for the specific language governing permissions and limitations", 100 | " * under the License.", 101 | " */", 102 | "", 103 | } 104 | 105 | // read file 106 | f, err := os.Open(filepath) 107 | if err != nil { 108 | fmt.Println(err) 109 | return err 110 | } 111 | 112 | var lines []string 113 | scanner := bufio.NewScanner(f) 114 | for scanner.Scan() { 115 | lines = append(lines, scanner.Text()) 116 | } 117 | if err := scanner.Err(); err != nil { 118 | fmt.Println(err) 119 | return err 120 | } 121 | 122 | f.Close() 123 | 124 | // recreate file with license 125 | file, err := os.OpenFile(filepath, os.O_CREATE|os.O_WRONLY, 0644) 126 | 127 | if err != nil { 128 | fmt.Println("failed creating file: %s", err) 129 | return err 130 | } 131 | 132 | datawriter := bufio.NewWriter(file) 133 | 134 | for _, data := range licensetxt { 135 | _, _ = datawriter.WriteString(data + "\n") 136 | } 137 | 138 | for _, data := range lines { 139 | _, _ = datawriter.WriteString(data + "\n") 140 | } 141 | 142 | datawriter.Flush() 143 | file.Close() 144 | return nil 145 | } 146 | --------------------------------------------------------------------------------