├── testutils
├── testutil_test.go
├── helper
│ ├── docker
│ │ └── Dockerfile
│ ├── helper_suite_test.go
│ ├── http_echo.go
│ └── testrunner.go
├── runners
│ └── ports.go
├── testutils_suite_test.go
├── logs.go
├── make.go
├── skip.go
├── goimpl
│ ├── goimpl_suite_test.go
│ ├── curl_test.go
│ └── curl.go
├── random.go
├── get_current_file_test.go
├── get_current_file.go
├── port
│ └── port.go
├── README.md
├── deploy_from_yaml.go
├── clusterlock
│ └── clusterlock_suite_test.go
├── assertions.go
├── deploy_testrunner.go
├── exec
│ └── cmd.go
├── testutil.go
├── fail_handler.go
├── kube
│ ├── kube_create.go
│ └── istio_teardown.go
└── trimmed_stack_fail_handler.go
├── wmanager
├── go.mod
└── README.md
├── grpcx
├── logo.png
├── go.mod
├── README.md
├── limiters.go
└── balancer.go
├── shell
├── logo.png
├── go.mod
├── go.sum
├── yum.go
└── README.md
├── healthutils
├── interface.go
├── healthchecker_suite_test.go
└── grpc.go
├── dockerutils
├── save.go
├── docker_suite_test.go
├── exec.go
├── pull.go
└── docker_test.go
├── logutils
├── logger.go
├── raw_logger_test.go
├── json_logger.go
├── raw_logger.go
├── log_s.go
├── dummylogger.go
├── json_logger_test.go
├── log_test.go
├── severity.go
├── log.go
├── defaultlogger.go
├── print_test.go
└── internal_logger.go
├── versionutils
├── dep
│ └── types.go
├── kubeapi
│ ├── kubeapi_suite_test.go
│ ├── list.go
│ └── list_test.go
├── versionutils_suite_test.go
└── cli.go
├── configutils
├── test
│ └── config_suite_test.go
├── config_map_client_mock.go
├── README.md
└── config_map_client.go
├── vfsutils
├── vfs_suite_test.go
├── vfs_test.go
├── mount_test.go
└── afero.go
├── certutils
├── certutils_suite_test.go
└── gen_cert_test.go
├── kubectrlutils
├── kubeutils_suite_test.go
├── pod_termination.go
├── wait_crd.go
├── namespaces.go
├── wait_crd_test.go
├── util.go
├── kube_cfg.go
└── util_test.go
├── kubesetuputils
├── shared_suite_test.go
├── kube_errs.go
├── crd.go
└── install_kube_manifest_test.go
├── nameutils
├── nameutils_suite_test.go
├── sanitize_name.go
└── sanitize_name_test.go
├── slackutils
├── slack_suite_test.go
├── http.go
└── slack.go
├── contextutils
├── time.go
└── errors_and_logging.go
├── botutils
├── consts.go
├── botconfig
│ ├── botconfig_suite_test.go
│ └── os_mock_test.go
├── README.md
├── interface.go
└── server.go
├── githubutils
├── githubutils_suite_test.go
└── README.md
├── pkgmgmtutils
└── pkgmgmtutils_suite_test.go
├── surveyutils
├── surveyutils_suite_test.go
└── input_test.go
├── kubeinstallutils
├── helmchart
│ ├── helmchart_suite_test.go
│ └── docs_test.go
├── installutils_suite_test.go
├── kubeinstall
│ ├── kubeinstall_suite_test.go
│ ├── mocks
│ │ └── mock_kube_installer.go
│ └── installer_callbacks.go
├── kuberesource
│ ├── kuberesource_suite_test.go
│ └── get_cluster_resources_test.go
├── manifests_test.go
├── test
│ └── inputs
│ │ └── input_manifest.go
└── manifests.go
├── .gitignore
├── protoutils
└── protoutil_suite_test.go
├── funcutils
├── rand.go
└── retry.go
├── errutils
├── aggregate_errs.go
├── errors.go
└── errors_test.go
├── fileutils
├── file_crud_test.go
├── messages.go
├── file_crud.go
├── messages_test.go
├── writter.go
└── tar_test.go
├── strutils
├── regex.go
├── hash.go
├── text.go
├── strings.go
├── url.go
├── colorstring_test.go
├── regex_test.go
└── freezable.go
├── .vscode
└── launch.json
├── osutils
└── client.go
├── manifestutils
├── test
│ └── example_suite_test.go
└── README.md
├── progressutils
├── wrapper_test.go
├── spinner_test.go
├── progress.go
├── wrapper.go
├── spinner.go
└── progress_test.go
├── commandutils
├── git
│ └── git.go
└── command_test.go
├── pkcs12utils
├── internal
│ └── rc2
│ │ ├── bench_test.go
│ │ └── rc2_test.go
├── errors.go
├── README.md
├── pbkdf_test.go
├── bmp-string.go
├── mac.go
├── bmp-string_test.go
└── mac_test.go
├── maputils
├── ordered_map_iterate.go
└── maputil.go
├── README.md
├── stats
├── runtime.go
└── README.md
├── sliceutils
├── sliceutil.go
└── sliceutil_test.go
├── debugutils
├── requests.go
├── test
│ ├── aggregator_test.go
│ ├── pods_test.go
│ └── resources_test.go
├── debugutils_suite_test.go
├── storage.go
├── mocks_kube_test.go
└── aggregator_test.go
├── builtinutils
└── builtinutil.go
├── envutils
└── vars.go
├── template_util
└── templateutil.go
├── pointersutils
└── pointers.go
└── parseutils
└── parseutil.go
/testutils/testutil_test.go:
--------------------------------------------------------------------------------
1 | package testutil
2 |
--------------------------------------------------------------------------------
/wmanager/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/rfyiamcool/wmanager
2 |
3 | go 1.14
4 |
--------------------------------------------------------------------------------
/grpcx/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wx-chevalier/ms-go-commons/master/grpcx/logo.png
--------------------------------------------------------------------------------
/shell/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wx-chevalier/ms-go-commons/master/shell/logo.png
--------------------------------------------------------------------------------
/healthutils/interface.go:
--------------------------------------------------------------------------------
1 | package healthchecker
2 |
3 | type HealthChecker interface {
4 | Fail()
5 | }
6 |
--------------------------------------------------------------------------------
/testutils/helper/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM cjimti/go-echo:latest
2 |
3 | RUN apk update
4 | RUN apk add curl
5 |
6 | WORKDIR /
7 |
8 | ENTRYPOINT ["/tcp-echo"]
--------------------------------------------------------------------------------
/dockerutils/save.go:
--------------------------------------------------------------------------------
1 | package docker
2 |
3 | // Save saves image to dest, as in `docker save`
4 | func Save(image, dest string) error {
5 | return Command("save", "-o", dest, image).Run()
6 | }
7 |
--------------------------------------------------------------------------------
/testutils/runners/ports.go:
--------------------------------------------------------------------------------
1 | package runners
2 |
3 | import "github.com/onsi/ginkgo"
4 |
5 | func AllocateParallelPort(basePort int) int {
6 | return basePort + (ginkgo.GinkgoParallelNode()-1)*20
7 | }
8 |
--------------------------------------------------------------------------------
/grpcx/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/rfyiamcool/grpcpp
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/pkg/errors v0.9.1
7 | golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
8 | google.golang.org/grpc v1.29.1
9 | )
10 |
--------------------------------------------------------------------------------
/logutils/logger.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | // Logger ...
4 | type Logger interface {
5 | Print(f Formatable)
6 | }
7 |
8 | // Formatable ...
9 | type Formatable interface {
10 | String() string
11 | JSON() string
12 | }
13 |
--------------------------------------------------------------------------------
/versionutils/dep/types.go:
--------------------------------------------------------------------------------
1 | package dep
2 |
3 | type VersionType int
4 |
5 | const (
6 | Revision VersionType = iota
7 | Version
8 | Branch
9 | )
10 |
11 | type VersionInfo struct {
12 | Version string
13 | Type VersionType
14 | }
15 |
--------------------------------------------------------------------------------
/configutils/test/config_suite_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestConfig(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Config Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/dockerutils/docker_suite_test.go:
--------------------------------------------------------------------------------
1 | package docker_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestDocker(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Docker Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/vfsutils/vfs_suite_test.go:
--------------------------------------------------------------------------------
1 | package vfsutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestVfsutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Vfsutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/testutils/helper/helper_suite_test.go:
--------------------------------------------------------------------------------
1 | package helper_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestHelper(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Helper Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/certutils/certutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package certutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestCertutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Certutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/kubectrlutils/kubeutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package kubeutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestKubeutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Kubeutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/kubesetuputils/shared_suite_test.go:
--------------------------------------------------------------------------------
1 | package kubeinstallutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestShared(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Shared Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/nameutils/nameutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package nameutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestNameutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Nameutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/shell/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/rfyiamcool/go-shell
2 |
3 | go 1.14
4 |
5 | require (
6 | github.com/pkg/errors v0.9.1
7 | github.com/stretchr/objx v0.2.0 // indirect
8 | github.com/stretchr/testify v1.6.1
9 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
10 | )
11 |
--------------------------------------------------------------------------------
/slackutils/slack_suite_test.go:
--------------------------------------------------------------------------------
1 | package slackutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestSlackutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Slackutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/testutils/testutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package testutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestTestutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Testutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/versionutils/kubeapi/kubeapi_suite_test.go:
--------------------------------------------------------------------------------
1 | package kubeapi_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestKubeApi(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Kube Api Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/contextutils/time.go:
--------------------------------------------------------------------------------
1 | package contextutils
2 |
3 | import (
4 | "context"
5 | "time"
6 | )
7 |
8 | func Sleep(ctx context.Context, amount time.Duration) error {
9 | select {
10 | case <-time.After(amount):
11 | return nil
12 | case <-ctx.Done():
13 | return ctx.Err()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/botutils/consts.go:
--------------------------------------------------------------------------------
1 | package botutils
2 |
3 | const (
4 | PrType = "pull_request"
5 | PrReviewType = "pull_request_review"
6 | IssueCommentType = "issue_comment"
7 | CommitCommentType = "commit_comment"
8 | ReleaseType = "release"
9 | IssuesType = "issues"
10 | )
11 |
--------------------------------------------------------------------------------
/githubutils/githubutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package githubutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestGithubutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Githubutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/pkgmgmtutils/pkgmgmtutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package pkgmgmtutils
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestPkgmgmtutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Pkgmgmtutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/surveyutils/surveyutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package surveyutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestSurveyutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Surveyutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/healthutils/healthchecker_suite_test.go:
--------------------------------------------------------------------------------
1 | package healthchecker_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestHealthchecker(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Healthchecker Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/kubeinstallutils/helmchart/helmchart_suite_test.go:
--------------------------------------------------------------------------------
1 | package helmchart_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestHelmchart(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Helmchart Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/kubeinstallutils/installutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package installutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestInstallutils(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Installutils Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/kubeinstallutils/kubeinstall/kubeinstall_suite_test.go:
--------------------------------------------------------------------------------
1 | package kubeinstall_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestKubeinstall(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Kubeinstall Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/kubeinstallutils/kuberesource/kuberesource_suite_test.go:
--------------------------------------------------------------------------------
1 | package kuberesource_test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | )
9 |
10 | func TestKuberesource(t *testing.T) {
11 | RegisterFailHandler(Fail)
12 | RunSpecs(t, "Kuberesource Suite")
13 | }
14 |
--------------------------------------------------------------------------------
/testutils/logs.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "github.com/fgrosse/zaptest"
5 | "github.com/wx-chevalier/go-utils/contextutils"
6 |
7 | . "github.com/onsi/ginkgo"
8 | )
9 |
10 | func SetupLog() {
11 | logger := zaptest.LoggerWriter(GinkgoWriter)
12 | contextutils.SetFallbackLogger(logger.Sugar())
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | # vendor/
16 |
--------------------------------------------------------------------------------
/protoutils/protoutil_suite_test.go:
--------------------------------------------------------------------------------
1 | package protoutils
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/wx-chevalier/go-utils/log"
7 |
8 | . "github.com/onsi/ginkgo"
9 | . "github.com/onsi/gomega"
10 | )
11 |
12 | func TestProtoutil(t *testing.T) {
13 | RegisterFailHandler(Fail)
14 | log.DefaultOut = GinkgoWriter
15 | RunSpecs(t, "Protoutil Suite")
16 | }
17 |
--------------------------------------------------------------------------------
/testutils/make.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "fmt"
5 | "os/exec"
6 | "strings"
7 |
8 | . "github.com/onsi/gomega"
9 | )
10 |
11 | func MustMake(dir, args string) {
12 | make := exec.Command("make", strings.Split(args, " ")...)
13 | make.Dir = dir
14 | out, err := make.CombinedOutput()
15 | if err != nil {
16 | fmt.Printf(string(out))
17 | }
18 | Expect(err).NotTo(HaveOccurred())
19 | }
20 |
--------------------------------------------------------------------------------
/testutils/skip.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/wx-chevalier/go-utils/log"
7 | )
8 |
9 | func AreTestsDisabled() bool {
10 | if os.Getenv("RUN_KUBE2E_TESTS") != "1" {
11 | log.Warnf("This test requires a running kubernetes cluster and is disabled by default. " +
12 | "To enable, set RUN_KUBE2E_TESTS=1 in your env.")
13 | return true
14 | }
15 | return false
16 | }
17 |
--------------------------------------------------------------------------------
/testutils/goimpl/goimpl_suite_test.go:
--------------------------------------------------------------------------------
1 | package goimpl
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/wx-chevalier/go-utils/testutils"
7 |
8 | . "github.com/onsi/ginkgo"
9 | )
10 |
11 | func TestGoImpl(t *testing.T) {
12 |
13 | testutils.RegisterPreFailHandler(
14 | func() {
15 | testutils.PrintTrimmedStack()
16 | })
17 | testutils.RegisterCommonFailHandlers()
18 | RunSpecs(t, "Go Impl Suite")
19 | }
20 |
--------------------------------------------------------------------------------
/funcutils/rand.go:
--------------------------------------------------------------------------------
1 | package randutils
2 |
3 | import (
4 | "math/rand"
5 | "time"
6 | )
7 |
8 | func init() {
9 | rand.Seed(time.Now().UnixNano())
10 | }
11 |
12 | var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz1234567890")
13 |
14 | func RandString(length int) string {
15 | b := make([]rune, length)
16 | for i := range b {
17 | b[i] = letterRunes[rand.Intn(len(letterRunes))]
18 | }
19 | return string(b)
20 | }
21 |
--------------------------------------------------------------------------------
/testutils/random.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "math/rand"
5 | "time"
6 | )
7 |
8 | func init() {
9 | rand.Seed(time.Now().UnixNano())
10 | }
11 |
12 | var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz1234567890")
13 |
14 | func RandString(length int) string {
15 | b := make([]rune, length)
16 | for i := range b {
17 | b[i] = letterRunes[rand.Intn(len(letterRunes))]
18 | }
19 | return string(b)
20 | }
21 |
--------------------------------------------------------------------------------
/versionutils/kubeapi/list.go:
--------------------------------------------------------------------------------
1 | package kubeapi
2 |
3 | // VersionList implements sort.Interface for a list of Kubernetes API version tags.
4 | type VersionList []Version
5 |
6 | func (list VersionList) Len() int {
7 | return len(list)
8 | }
9 |
10 | func (list VersionList) Less(i, j int) bool {
11 | return list[i].LessThan(list[j])
12 | }
13 |
14 | func (list VersionList) Swap(i, j int) {
15 | list[i], list[j] = list[j], list[i]
16 | }
17 |
--------------------------------------------------------------------------------
/errutils/aggregate_errs.go:
--------------------------------------------------------------------------------
1 | package errutils
2 |
3 | import (
4 | "context"
5 | )
6 |
7 | func AggregateErrs(ctx context.Context, dest chan error, src <-chan error, srcInfo string) {
8 | for {
9 | select {
10 | case err, ok := <-src:
11 | if !ok {
12 | return
13 | }
14 | select {
15 | case <-ctx.Done():
16 | return
17 | case dest <- Wrapf(err, srcInfo):
18 | }
19 | case <-ctx.Done():
20 | return
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/fileutils/file_crud_test.go:
--------------------------------------------------------------------------------
1 | package fileutils
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestCopyFileErrorIfDirectory(t *testing.T) {
10 | t.Log("It fails if source is a directory")
11 | {
12 | tmpFolder, err := NormalizedOSTempDirPath("_tmp")
13 | require.NoError(t, err)
14 | require.EqualError(t, CopyFile(tmpFolder, "./nothing/whatever"), "Source is a directory: "+tmpFolder)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/logutils/raw_logger_test.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestRawPrint(t *testing.T) {
11 | t.Log("Custom Formattable")
12 | {
13 | var b bytes.Buffer
14 | logger := NewRawLogger(&b)
15 |
16 | test := TestFormattable{
17 | A: "log",
18 | B: "test",
19 | }
20 |
21 | logger.Print(test)
22 | require.Equal(t, "log test\n", b.String())
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/strutils/regex.go:
--------------------------------------------------------------------------------
1 | package regexputil
2 |
3 | import "regexp"
4 |
5 | // NamedFindStringSubmatch ...
6 | func NamedFindStringSubmatch(rexp *regexp.Regexp, text string) (map[string]string, bool) {
7 | match := rexp.FindStringSubmatch(text)
8 | if match == nil {
9 | return nil, false
10 | }
11 | result := map[string]string{}
12 | for i, name := range rexp.SubexpNames() {
13 | if i != 0 {
14 | result[name] = match[i]
15 | }
16 | }
17 | return result, true
18 | }
19 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // 使用 IntelliSense 了解相关属性。
3 | // 悬停以查看现有属性的描述。
4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Launch",
9 | "type": "go",
10 | "request": "launch",
11 | "mode": "auto",
12 | "program": "${fileDirname}",
13 | "env": {},
14 | "args": []
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/testutils/get_current_file_test.go:
--------------------------------------------------------------------------------
1 | package testutils_test
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 |
7 | . "github.com/wx-chevalier/go-utils/testutils"
8 | )
9 |
10 | var _ = Describe("GetCurrentFileDirectory", func() {
11 | It("works", func() {
12 | f, err := GetCurrentFile()
13 | Expect(err).NotTo(HaveOccurred())
14 | Expect(f).To(HaveSuffix("testutils/get_current_file_test.go"))
15 | Expect(f).To(HavePrefix("/"))
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/testutils/get_current_file.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "path/filepath"
5 | "runtime"
6 |
7 | "github.com/wx-chevalier/go-utils/errutils"
8 | )
9 |
10 | // returns the absolute path to the file the caller
11 | // intended to provide a way to find test files
12 | func GetCurrentFile() (string, error) {
13 | _, callerFile, _, ok := runtime.Caller(1)
14 | if !ok {
15 | return "", errors.Errorf("failed to get runtime.Caller")
16 | }
17 | return filepath.Abs(callerFile)
18 | }
19 |
--------------------------------------------------------------------------------
/versionutils/versionutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package versionutils_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/wx-chevalier/go-utils/testutils"
7 |
8 | . "github.com/onsi/ginkgo"
9 | . "github.com/onsi/gomega"
10 | )
11 |
12 | func TestVersionUtils(t *testing.T) {
13 | RegisterFailHandler(Fail)
14 | testutils.RegisterPreFailHandler(
15 | func() {
16 | testutils.PrintTrimmedStack()
17 | })
18 | testutils.RegisterCommonFailHandlers()
19 | RunSpecs(t, "Versionutils Suite")
20 | }
21 |
--------------------------------------------------------------------------------
/versionutils/cli.go:
--------------------------------------------------------------------------------
1 | package versionutils
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | )
7 |
8 | func GetReleaseVersionOrExitGracefully() *Version {
9 | tag, present := os.LookupEnv("TAGGED_VERSION")
10 | if !present || tag == "" {
11 | fmt.Printf("TAGGED_VERSION not found in environment.\n")
12 | os.Exit(0)
13 | }
14 | version, err := ParseVersion(tag)
15 | if err != nil {
16 | fmt.Printf("TAGGED_VERSION %s is not a valid semver version.\n", tag)
17 | os.Exit(0)
18 | }
19 | return version
20 | }
21 |
--------------------------------------------------------------------------------
/osutils/client.go:
--------------------------------------------------------------------------------
1 | package osutils
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | )
7 |
8 | type OsClient interface {
9 | Getenv(key string) string
10 | ReadFile(path string) ([]byte, error)
11 | }
12 |
13 | type osClient struct {
14 | }
15 |
16 | func (*osClient) Getenv(key string) string {
17 | return os.Getenv(key)
18 | }
19 |
20 | func (*osClient) ReadFile(path string) ([]byte, error) {
21 | return ioutil.ReadFile(path)
22 | }
23 |
24 | func NewOsClient() OsClient {
25 | return &osClient{}
26 | }
27 |
--------------------------------------------------------------------------------
/manifestutils/test/example_suite_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 |
6 | . "github.com/wx-chevalier/go-utils/manifesttestutils"
7 |
8 | . "github.com/onsi/ginkgo"
9 | . "github.com/onsi/gomega"
10 | )
11 |
12 | func TestManifestTestUtils(t *testing.T) {
13 | RegisterFailHandler(Fail)
14 | RunSpecs(t, "ManifestTestUtils Suite")
15 | }
16 |
17 | var (
18 | testManifest TestManifest
19 | )
20 |
21 | var _ = BeforeSuite(func() {
22 | testManifest = NewTestManifest("example.yaml")
23 | })
24 |
--------------------------------------------------------------------------------
/testutils/port/port.go:
--------------------------------------------------------------------------------
1 | package port
2 |
3 | import (
4 | "sync/atomic"
5 |
6 | "github.com/onsi/ginkgo/config"
7 | )
8 |
9 | var MaxTests = 1000
10 |
11 | type TestPort struct {
12 | port *uint32
13 | }
14 |
15 | // Helps you get a free port with ginkgo tests.
16 | func NewTestPort(initial uint32) TestPort {
17 | return TestPort{
18 | port: &initial,
19 | }
20 | }
21 |
22 | func (t TestPort) NextPort() uint32 {
23 | return atomic.AddUint32(t.port, 1) + uint32(config.GinkgoConfig.ParallelNode*MaxTests)
24 | }
25 |
--------------------------------------------------------------------------------
/kubeinstallutils/manifests_test.go:
--------------------------------------------------------------------------------
1 | package installutils_test
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 | "github.com/wx-chevalier/go-utils/installutils"
7 | )
8 |
9 | var _ = Describe("Manifests", func() {
10 | It("works", func() {
11 | manifests, err := installutils.GetManifestsFromRemoteTar("https://github.com/XiaoMi/naftis/releases/download/0.1.4-rc6/manifest.tar.gz")
12 | Expect(err).NotTo(HaveOccurred())
13 | Expect(len(manifests)).To(BeEquivalentTo(3))
14 | })
15 | })
16 |
--------------------------------------------------------------------------------
/testutils/goimpl/curl_test.go:
--------------------------------------------------------------------------------
1 | package goimpl
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 | )
7 |
8 | var _ = Describe("Curl", func() {
9 |
10 | It("should query a url", func() {
11 | soloResp, err := Curl("https://www.solo.io")
12 | Expect(err).NotTo(HaveOccurred())
13 | Expect(len(soloResp)).To(BeNumerically(">", 0))
14 | })
15 |
16 | It("should error on invalid url", func() {
17 | _, err := Curl("invalid://www.solo.io")
18 | Expect(err).To(HaveOccurred())
19 | })
20 |
21 | })
22 |
--------------------------------------------------------------------------------
/botutils/botconfig/botconfig_suite_test.go:
--------------------------------------------------------------------------------
1 | package botconfig_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/wx-chevalier/go-utils/testutils"
7 |
8 | . "github.com/onsi/ginkgo"
9 | . "github.com/onsi/gomega"
10 | )
11 |
12 | func TestBotconfig(t *testing.T) {
13 | test = t
14 | RegisterFailHandler(Fail)
15 | testutils.RegisterPreFailHandler(
16 | func() {
17 | testutils.PrintTrimmedStack()
18 | })
19 | testutils.RegisterCommonFailHandlers()
20 | RunSpecs(t, "Botconfig Suite")
21 | }
22 |
23 | var test *testing.T
24 |
--------------------------------------------------------------------------------
/kubeinstallutils/test/inputs/input_manifest.go:
--------------------------------------------------------------------------------
1 | package inputs
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/wx-chevalier/go-utils/installutils/helmchart"
7 |
8 | "github.com/onsi/gomega"
9 | )
10 |
11 | func InputGlooManifests(ns string) helmchart.Manifests {
12 | manifests, err := helmchart.RenderManifests(
13 | context.TODO(),
14 | "https://storage.googleapis.com/solo-public-helm/charts/gloo-1.0.0.tgz",
15 | "",
16 | "yella",
17 | ns,
18 | "",
19 | )
20 | gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred())
21 | return manifests
22 | }
23 |
--------------------------------------------------------------------------------
/progressutils/wrapper_test.go:
--------------------------------------------------------------------------------
1 | // +build !race
2 |
3 | package progress
4 |
5 | import (
6 | "testing"
7 | "time"
8 | )
9 |
10 | func TestNewWrapper(t *testing.T) {
11 | message := "loading"
12 | spinner := NewDefaultSpinner(message)
13 |
14 | isInteractiveMode := true
15 | NewWrapper(spinner, isInteractiveMode).WrapAction(func() {
16 | time.Sleep(2 * time.Second)
17 | })
18 | }
19 |
20 | func TestNewDefaultWrapper(t *testing.T) {
21 | message := "loading"
22 | NewDefaultWrapper(message).WrapAction(func() {
23 | time.Sleep(2 * time.Second)
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/nameutils/sanitize_name.go:
--------------------------------------------------------------------------------
1 | package nameutils
2 |
3 | import (
4 | "crypto/md5"
5 | "fmt"
6 | "strings"
7 | )
8 |
9 | var badChars = []rune{
10 | '.',
11 | '_',
12 | }
13 |
14 | // sanitize name to make it clean for writing kubernetes objects
15 | func SanitizeName(name string) string {
16 | name = strings.Map(func(r rune) rune {
17 | for _, badChar := range badChars {
18 | if r == badChar {
19 | return '-'
20 | }
21 | }
22 | return r
23 | }, name)
24 | if len(name) > 63 {
25 | hash := md5.Sum([]byte(name))
26 | name = fmt.Sprintf("%s-%x", name[:46], hash[:8])
27 | }
28 | return name
29 | }
30 |
--------------------------------------------------------------------------------
/grpcx/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## grpcx
4 |
5 | `grpcx` golang grpc common
6 |
7 | ## Desc
8 |
9 | **middleware**
10 |
11 | * unary
12 | * stream
13 |
14 | **interceptor**
15 |
16 | * logger
17 | * try catch
18 | * rate limiter
19 | * set custom logger
20 |
21 | **get ip info**
22 |
23 | * get real ip
24 | * get peer ip
25 |
26 | **creds**
27 |
28 | * easy new server creds
29 | * easy new client creds
30 |
31 | **conn state**
32 |
33 | * check grpc connection state
34 |
35 | **status code**
36 |
37 | * easy new status
38 | * check status
39 | * diff error
40 |
--------------------------------------------------------------------------------
/commandutils/git/git.go:
--------------------------------------------------------------------------------
1 | package git
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/wx-chevalier/go-utils/commandutils"
7 | )
8 |
9 | // Git represents a Git project.
10 | type Git struct {
11 | dir string
12 | }
13 |
14 | // New creates a new git project.
15 | func New(dir string) (Git, error) {
16 | if err := os.MkdirAll(dir, 0755); err != nil {
17 | return Git{}, err
18 | }
19 | return Git{dir: dir}, nil
20 | }
21 |
22 | func (g *Git) command(args ...string) *command.Model {
23 | cmd := command.New("git", args...)
24 | cmd.SetDir(g.dir)
25 | cmd.SetEnvs(append(os.Environ(), "GIT_ASKPASS=echo")...)
26 | return cmd
27 | }
28 |
--------------------------------------------------------------------------------
/progressutils/spinner_test.go:
--------------------------------------------------------------------------------
1 | // +build !race
2 |
3 | package progress
4 |
5 | import (
6 | "os"
7 | "testing"
8 | "time"
9 | )
10 |
11 | func TestNewSpinner(t *testing.T) {
12 | message := "loading"
13 | chars := []string{"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"}
14 | delay := 100 * time.Millisecond
15 | writer := os.Stdout
16 |
17 | spinner := NewSpinner(message, chars, delay, writer)
18 | spinner.Start()
19 | time.Sleep(2 * time.Second)
20 | spinner.Stop()
21 | }
22 |
23 | func TestNewDefaultSpinner(t *testing.T) {
24 | message := "loading"
25 | spinner := NewDefaultSpinner(message)
26 | spinner.Start()
27 | time.Sleep(2 * time.Second)
28 | spinner.Stop()
29 | }
30 |
--------------------------------------------------------------------------------
/logutils/json_logger.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | )
8 |
9 | // JSONLoger ...
10 | type JSONLoger struct {
11 | writer io.Writer
12 | }
13 |
14 | // NewJSONLoger ...
15 | func NewJSONLoger(writer io.Writer) *JSONLoger {
16 | return &JSONLoger{
17 | writer: writer,
18 | }
19 | }
20 |
21 | // NewDefaultJSONLoger ...
22 | func NewDefaultJSONLoger() JSONLoger {
23 | return JSONLoger{
24 | writer: os.Stdout,
25 | }
26 | }
27 |
28 | // Print ...
29 | func (l JSONLoger) Print(f Formatable) {
30 | if _, err := fmt.Fprint(l.writer, f.JSON()); err != nil {
31 | fmt.Printf("failed to print message: %s, error: %s\n", f.JSON(), err)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/logutils/raw_logger.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | )
8 |
9 | // RawLogger ...
10 | type RawLogger struct {
11 | writer io.Writer
12 | }
13 |
14 | // NewRawLogger ...
15 | func NewRawLogger(writer io.Writer) *RawLogger {
16 | return &RawLogger{
17 | writer: writer,
18 | }
19 | }
20 |
21 | // NewDefaultRawLogger ...
22 | func NewDefaultRawLogger() RawLogger {
23 | return RawLogger{
24 | writer: os.Stdout,
25 | }
26 | }
27 |
28 | // Print ...
29 | func (l RawLogger) Print(f Formatable) {
30 | if _, err := fmt.Fprintln(l.writer, f.String()); err != nil {
31 | fmt.Printf("failed to print message: %s, error: %s\n", f.String(), err)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/logutils/log_s.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | "time"
8 | )
9 |
10 | var outWriter io.Writer = os.Stdout
11 |
12 | // SetOutWriter ...
13 | func SetOutWriter(writer io.Writer) {
14 | outWriter = writer
15 | }
16 |
17 | var enableDebugLog = false
18 |
19 | // SetEnableDebugLog ...
20 | func SetEnableDebugLog(enable bool) {
21 | enableDebugLog = enable
22 | }
23 |
24 | var timestampLayout = "15:04:05"
25 |
26 | // SetTimestampLayout ...
27 | func SetTimestampLayout(layout string) {
28 | timestampLayout = layout
29 | }
30 |
31 | func timestampField() string {
32 | currentTime := time.Now()
33 | return fmt.Sprintf("[%s]", currentTime.Format(timestampLayout))
34 | }
35 |
--------------------------------------------------------------------------------
/pkcs12utils/internal/rc2/bench_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package rc2
6 |
7 | import (
8 | "testing"
9 | )
10 |
11 | func BenchmarkEncrypt(b *testing.B) {
12 | r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64)
13 | b.ResetTimer()
14 | var src [8]byte
15 | for i := 0; i < b.N; i++ {
16 | r.Encrypt(src[:], src[:])
17 | }
18 | }
19 |
20 | func BenchmarkDecrypt(b *testing.B) {
21 | r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64)
22 | b.ResetTimer()
23 | var src [8]byte
24 | for i := 0; i < b.N; i++ {
25 | r.Decrypt(src[:], src[:])
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/nameutils/sanitize_name_test.go:
--------------------------------------------------------------------------------
1 | package nameutils_test
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 | "k8s.io/apimachinery/pkg/util/validation"
7 |
8 | . "github.com/wx-chevalier/go-utils/nameutils"
9 | )
10 |
11 | var _ = Describe("SanitizeName", func() {
12 | expected := "istio-release-testu4j66c6y-details-istio-routi-59cd38e6f450a2fd"
13 | It("makes names dns-compliant", func() {
14 | name := "istio-release-testu4j66c6y-details-istio-routing-testfi4kb3wb-svc-cluster-local"
15 | actual := SanitizeName(name)
16 | Expect(len(actual)).To(Equal(63))
17 | Expect(actual).To(Equal(expected))
18 | Expect(validation.IsDNS1123Label(actual)).To(HaveLen(0))
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/vfsutils/vfs_test.go:
--------------------------------------------------------------------------------
1 | package vfsutils_test
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 | "github.com/wx-chevalier/go-utils/vfsutils"
7 | "github.com/spf13/afero"
8 | )
9 |
10 | var _ = Describe("vfsutils", func() {
11 | Context("MountTar", func() {
12 | It("works", func() {
13 | fs := afero.NewMemMapFs()
14 | dir, err := vfsutils.MountTar(fs, "https://github.com/XiaoMi/naftis/releases/download/0.1.4-rc6/manifest.tar.gz")
15 | Expect(err).NotTo(HaveOccurred())
16 | Expect(dir).NotTo(BeEquivalentTo(""))
17 | files, err := afero.ReadDir(fs, dir)
18 | Expect(err).NotTo(HaveOccurred())
19 | Expect(len(files)).To(BeEquivalentTo(3))
20 | })
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/testutils/goimpl/curl.go:
--------------------------------------------------------------------------------
1 | package goimpl
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | "net/http"
7 | )
8 |
9 | // Curl provides some of the functionality you would expect from the curl command.
10 | // This saves you from having to call the curl binary in environments where that binary is not available.
11 | func Curl(url string) (string, error) {
12 | body := bytes.NewReader([]byte(url))
13 | req, err := http.NewRequest("GET", url, body)
14 | if err != nil {
15 | return "", err
16 | }
17 |
18 | resp, err := http.DefaultClient.Do(req)
19 | if err != nil {
20 | return "", err
21 | }
22 | p := new(bytes.Buffer)
23 | _, err = io.Copy(p, resp.Body)
24 | defer resp.Body.Close()
25 |
26 | return p.String(), nil
27 | }
28 |
--------------------------------------------------------------------------------
/kubesetuputils/kube_errs.go:
--------------------------------------------------------------------------------
1 | package kubeerrutils
2 |
3 | import (
4 | "strings"
5 |
6 | kubeerrs "k8s.io/apimachinery/pkg/api/errors"
7 | "k8s.io/apimachinery/pkg/api/validation"
8 | )
9 |
10 | const ObjectIsBeingDeletedErrorMsg = "object is being deleted"
11 |
12 | func IsImmutableErr(err error) bool {
13 | if err != nil {
14 | return kubeerrs.IsInvalid(err) && strings.Contains(err.Error(), validation.FieldImmutableErrorMsg)
15 | }
16 | return false
17 | }
18 |
19 | // is the error AlreadyExists && the resource is not terminating?
20 | func IsAlreadyExists(err error) bool {
21 | if err != nil {
22 | return kubeerrs.IsAlreadyExists(err) && !strings.Contains(err.Error(), ObjectIsBeingDeletedErrorMsg)
23 | }
24 | return false
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/maputils/ordered_map_iterate.go:
--------------------------------------------------------------------------------
1 | package maputils
2 |
3 | import (
4 | "sort"
5 | )
6 |
7 | // thank you R.P.
8 | // TODO(ilackarms): find a better way to solve generics than interface{}
9 | // consider using go-utils to generate
10 | func OrderedMapIterator(m map[string]interface{}, onKey func(key string, value interface{})) {
11 | var list []struct {
12 | key string
13 | value interface{}
14 | }
15 | for k, v := range m {
16 | list = append(list, struct {
17 | key string
18 | value interface{}
19 | }{
20 | key: k,
21 | value: v,
22 | })
23 | }
24 | sort.SliceStable(list, func(i, j int) bool {
25 | return list[i].key < list[j].key
26 | })
27 | for _, el := range list {
28 | onKey(el.key, el.value)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/strutils/hash.go:
--------------------------------------------------------------------------------
1 | package hashutils
2 |
3 | import (
4 | "github.com/mitchellh/hashstructure"
5 | )
6 |
7 | // Hashers are resources which have a custom hashing function defined.
8 | // Hash functions are generated by default for go-utils resources
9 | type Hasher interface {
10 | Hash() uint64
11 | }
12 |
13 | // hash one or more values
14 | // order matters
15 | func HashAll(values ...interface{}) uint64 {
16 | var hashes []uint64
17 | for _, v := range values {
18 | hashes = append(hashes, hashValue(v))
19 | }
20 | return hashValue(hashes)
21 | }
22 |
23 | func hashValue(val interface{}) uint64 {
24 | if hasher, ok := val.(Hasher); ok {
25 | return hasher.Hash()
26 | }
27 | h, err := hashstructure.Hash(val, nil)
28 | if err != nil {
29 | panic("resource failed to hash: " + err.Error())
30 | }
31 | return h
32 | }
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Go Utils
4 |
5 |
6 | This repo contains common utilities for go projects.
7 |
8 | > 更多 Go 学习笔记参考 [:books: Go-Series, Go From Zero to Hero. | 语法基础、工程实践、并发编程、Web 开发](https://github.com/wx-chevalier/Go-Series)。
9 |
10 | # About
11 |
12 | - [go-realworld-clean #Project#](https://github.com/err0r500/go-realworld-clean): Golang clean-architecture codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API.
13 |
14 | - [golang-gin-realworld-example-app](https://github.com/gothinkster/golang-gin-realworld-example-app)
15 |
16 | - [d3ta-go](https://github.com/muharihar/d3ta-go): A Simple Implementation of Domain-Driven Design Technical Architecture Patterns in Go.
17 |
--------------------------------------------------------------------------------
/logutils/dummylogger.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | // DummyLogger ...
4 | type DummyLogger struct{}
5 |
6 | // NewDummyLogger ...
7 | func NewDummyLogger() DummyLogger {
8 | return DummyLogger{}
9 | }
10 |
11 | // Donef ...
12 | func (dl DummyLogger) Donef(format string, v ...interface{}) {}
13 |
14 | // Successf ...
15 | func (dl DummyLogger) Successf(format string, v ...interface{}) {}
16 |
17 | // Infof ...
18 | func (dl DummyLogger) Infof(format string, v ...interface{}) {}
19 |
20 | // Printf ...
21 | func (dl DummyLogger) Printf(format string, v ...interface{}) {}
22 |
23 | // Debugf ...
24 | func (dl DummyLogger) Debugf(format string, v ...interface{}) {}
25 |
26 | // Warnf ...
27 | func (dl DummyLogger) Warnf(format string, v ...interface{}) {}
28 |
29 | // Errorf ...
30 | func (dl DummyLogger) Errorf(format string, v ...interface{}) {}
31 |
--------------------------------------------------------------------------------
/testutils/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Fail Handlers
3 |
4 | ## PrintTrimmedStack
5 |
6 | The `PrintTrimmedStack` fail handler simplifies error tracking in ginkgo tests by printing a condensed stack trace upon failure. Printout excludes well-known overhead files so you can more easily sight the failing line. This eliminates the need to count stack offset via `ExpectWithOffset`. You can just use `Expect`.
7 |
8 |
9 | ### Usage
10 |
11 | To use, register `PrintTrimmedStack` as a prefail handler with `RegisterPreFailHandler` in your `ginkgo` suite:
12 |
13 | ```go
14 | func TestCliCore(t *testing.T) {
15 |
16 | testutils.RegisterPreFailHandler(
17 | func() {
18 | testutils.PrintTrimmedStack()
19 | })
20 | testutils.RegisterCommonFailHandlers()
21 | RegisterFailHandler(Fail)
22 | testutils.SetupLog()
23 | RunSpecs(t, "Clicore Suite")
24 | }
25 | ```
--------------------------------------------------------------------------------
/configutils/config_map_client_mock.go:
--------------------------------------------------------------------------------
1 | package configutils
2 |
3 | import (
4 | "context"
5 |
6 | v1 "k8s.io/api/core/v1"
7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | )
9 |
10 | type MockConfigMapClient struct {
11 | Data map[string]string
12 | GetError error
13 | SetError error
14 | }
15 |
16 | func (c *MockConfigMapClient) GetConfigMap(ctx context.Context, namespace string, name string) (*v1.ConfigMap, error) {
17 | if c.GetError != nil {
18 | return nil, c.GetError
19 | }
20 | return &v1.ConfigMap{
21 | ObjectMeta: metav1.ObjectMeta{
22 | Namespace: namespace,
23 | Name: name,
24 | },
25 | Data: c.Data,
26 | }, nil
27 | }
28 |
29 | func (c *MockConfigMapClient) SetConfigMap(ctx context.Context, configMap *v1.ConfigMap) error {
30 | if c.SetError != nil {
31 | return c.SetError
32 | }
33 | return nil
34 | }
35 |
--------------------------------------------------------------------------------
/pkcs12utils/errors.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package pkcs12
6 |
7 | import "errors"
8 |
9 | var (
10 | // ErrDecryption represents a failure to decrypt the input.
11 | ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding")
12 |
13 | // ErrIncorrectPassword is returned when an incorrect password is detected.
14 | // Usually, P12/PFX data is signed to be able to verify the password.
15 | ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect")
16 | )
17 |
18 | // NotImplementedError indicates that the input is not currently supported.
19 | type NotImplementedError string
20 |
21 | func (e NotImplementedError) Error() string {
22 | return "pkcs12: " + string(e)
23 | }
24 |
--------------------------------------------------------------------------------
/logutils/json_logger_test.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | type TestFormattable struct {
12 | A string `json:"a,omitempty"`
13 | B string `json:"b,omitempty"`
14 | }
15 |
16 | // String ...
17 | func (f TestFormattable) String() string {
18 | return fmt.Sprintf("%s %s", f.A, f.B)
19 | }
20 |
21 | // JSON ...
22 | func (f TestFormattable) JSON() string {
23 | return fmt.Sprintf(`{"a":"%s","b":"%s"}`, f.A, f.B)
24 | }
25 |
26 | func TestJSONPrint(t *testing.T) {
27 |
28 | t.Log("Custom Formattable")
29 | {
30 | var b bytes.Buffer
31 | logger := NewJSONLoger(&b)
32 |
33 | test := TestFormattable{
34 | A: "log",
35 | B: "test",
36 | }
37 |
38 | logger.Print(test)
39 | require.Equal(t, `{"a":"log","b":"test"}`, b.String())
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/fileutils/messages.go:
--------------------------------------------------------------------------------
1 | package fileutils
2 |
3 | import (
4 | "io/ioutil"
5 |
6 | "github.com/ghodss/yaml"
7 | "github.com/gogo/protobuf/proto"
8 | "github.com/pkg/errors"
9 | protoutils "github.com/wx-chevalier/go-utils/protoutils"
10 | )
11 |
12 | func WriteToFile(filename string, pb proto.Message) error {
13 | jsn, err := protoutils.MarshalBytes(pb)
14 | if err != nil {
15 | return err
16 | }
17 | data, err := yaml.JSONToYAML(jsn)
18 | if err != nil {
19 | return err
20 | }
21 | return ioutil.WriteFile(filename, data, 0644)
22 | }
23 |
24 | func ReadFileInto(filename string, v proto.Message) error {
25 | data, err := ioutil.ReadFile(filename)
26 | if err != nil {
27 | return errors.Errorf("error reading file: %v", err)
28 | }
29 | jsn, err := yaml.YAMLToJSON(data)
30 | if err != nil {
31 | return err
32 | }
33 | return protoutils.UnmarshalBytes(jsn, v)
34 | }
35 |
--------------------------------------------------------------------------------
/botutils/README.md:
--------------------------------------------------------------------------------
1 | # Botutils
2 |
3 | This package contains utilities for writing simple git bot applications.
4 |
5 | ## Implementing hooks
6 |
7 | Write a plugin that implements one or more of the handler interfaces defined in `interface.go`.
8 |
9 | ## Implementing a server
10 |
11 | Create an instance of SimpleGitBot:
12 |
13 | ```go
14 | func Run(ctx context.Context) error {
15 | staticCfg := botutils.StaticBotConfig{BotName: BotName, Version: version.Version}
16 | bot := botutils.NewSimpleGitBot(staticCfg)
17 | return bot.Start(context.TODO(), plugins...)
18 | }
19 | ```
20 |
21 | ## Deploying the bot
22 |
23 | The bot needs to be deployed with a config that can be deserialized into the `botconfig.Config` struct. By default,
24 | this should be available at `/etc/solo-github-app/config.yml`, but can be mounted to a custom location
25 | by setting the `BOT_CONFIG` environment variable.
--------------------------------------------------------------------------------
/testutils/deploy_from_yaml.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "github.com/wx-chevalier/go-utils/kubeinstallutils"
5 | "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
6 | "k8s.io/client-go/kubernetes"
7 | "k8s.io/client-go/rest"
8 | )
9 |
10 | func DeployFromYaml(cfg *rest.Config, namespace, yamlManifest string) error {
11 | kube, err := kubernetes.NewForConfig(cfg)
12 | if err != nil {
13 | return err
14 | }
15 |
16 | apiext, err := clientset.NewForConfig(cfg)
17 | if err != nil {
18 | return err
19 | }
20 |
21 | installer := kubeinstallutils.NewKubeInstaller(kube, apiext, namespace)
22 |
23 | kubeObjs, err := kubeinstallutils.ParseKubeManifest(yamlManifest)
24 | if err != nil {
25 | return err
26 | }
27 |
28 | for _, kubeOjb := range kubeObjs {
29 | if err := installer.Create(kubeOjb); err != nil {
30 | return err
31 | }
32 | }
33 | return nil
34 | }
35 |
--------------------------------------------------------------------------------
/stats/runtime.go:
--------------------------------------------------------------------------------
1 | package stats
2 |
3 | import (
4 | "context"
5 | "runtime"
6 | "time"
7 |
8 | "go.opencensus.io/stats"
9 | "go.opencensus.io/stats/view"
10 | )
11 |
12 | var (
13 | MNumGoRoutines = stats.Int64("runtime/goroutines", "The number of goroutines", "1")
14 |
15 | GoroutinesNumView = &view.View{
16 | Name: "runtime/goroutines",
17 | Measure: MNumGoRoutines,
18 | Description: "The number of goroutines",
19 | Aggregation: view.Sum(),
20 | }
21 | )
22 |
23 | func init() {
24 | view.Register(GoroutinesNumView)
25 | }
26 |
27 | func RunGoroutineStat() {
28 | numgoroutines := int64(0)
29 | for {
30 | time.Sleep(time.Second)
31 | newnumgoroutines := int64(runtime.NumGoroutine())
32 | diff := newnumgoroutines - numgoroutines
33 | numgoroutines = newnumgoroutines
34 | if diff != 0 {
35 | stats.Record(context.TODO(), MNumGoRoutines.M(diff))
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/sliceutils/sliceutil.go:
--------------------------------------------------------------------------------
1 | package sliceutil
2 |
3 | // UniqueStringSlice - returns a cleaned up list,
4 | // where every item is unique.
5 | // Does NOT guarantee any ordering, the result can
6 | // be in any order!
7 | func UniqueStringSlice(strs []string) []string {
8 | lookupMap := map[string]interface{}{}
9 | for _, aStr := range strs {
10 | lookupMap[aStr] = 1
11 | }
12 | uniqueStrs := []string{}
13 | for k := range lookupMap {
14 | uniqueStrs = append(uniqueStrs, k)
15 | }
16 | return uniqueStrs
17 | }
18 |
19 | // IndexOfStringInSlice ...
20 | func IndexOfStringInSlice(searchFor string, searchIn []string) int {
21 | for idx, anItm := range searchIn {
22 | if anItm == searchFor {
23 | return idx
24 | }
25 | }
26 | return -1
27 | }
28 |
29 | // IsStringInSlice ...
30 | func IsStringInSlice(searchFor string, searchIn []string) bool {
31 | return IndexOfStringInSlice(searchFor, searchIn) >= 0
32 | }
33 |
--------------------------------------------------------------------------------
/progressutils/progress.go:
--------------------------------------------------------------------------------
1 | package progress
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | // SimpleProgressE ...
9 | func SimpleProgressE(printChar string, tickInterval time.Duration, action func() error) error {
10 | var actionError error
11 | SimpleProgress(printChar, tickInterval, func() {
12 | actionError = action()
13 | })
14 | return actionError
15 | }
16 |
17 | // SimpleProgress ...
18 | // action : have to be a synchronous action!
19 | // tickInterval : e.g. : 5000 * time.Millisecond
20 | func SimpleProgress(printChar string, tickInterval time.Duration, action func()) {
21 | // run async
22 | finishedChan := make(chan bool)
23 |
24 | go func() {
25 | action()
26 | finishedChan <- true
27 | }()
28 |
29 | isRunFinished := false
30 | for !isRunFinished {
31 | select {
32 | case <-finishedChan:
33 | isRunFinished = true
34 | case <-time.Tick(tickInterval):
35 | fmt.Print(printChar)
36 | }
37 | }
38 | fmt.Println()
39 | }
40 |
--------------------------------------------------------------------------------
/debugutils/requests.go:
--------------------------------------------------------------------------------
1 | package debugutils
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "path/filepath"
7 |
8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | "k8s.io/client-go/rest"
10 | )
11 |
12 | type LogMeta struct {
13 | PodMeta metav1.ObjectMeta
14 | ContainerName string
15 | }
16 |
17 | type LogsRequest struct {
18 | LogMeta
19 | Request rest.ResponseWrapper
20 | }
21 |
22 | type LogsResponse struct {
23 | LogMeta
24 | Response io.ReadCloser
25 | }
26 |
27 | func (lr LogMeta) ResourcePath(dir string) string {
28 | return filepath.Join(dir, lr.ResourceId())
29 | }
30 |
31 | func (lr LogMeta) ResourceId() string {
32 | return fmt.Sprintf("%s_%s_%s.log", lr.PodMeta.Namespace, lr.PodMeta.Name, lr.ContainerName)
33 | }
34 |
35 | func NewLogsRequest(podMeta metav1.ObjectMeta, containerName string, request *rest.Request) *LogsRequest {
36 | return &LogsRequest{LogMeta: LogMeta{PodMeta: podMeta, ContainerName: containerName}, Request: request}
37 | }
38 |
--------------------------------------------------------------------------------
/certutils/gen_cert_test.go:
--------------------------------------------------------------------------------
1 | package certutils_test
2 |
3 | import (
4 | "crypto/x509"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 |
9 | . "github.com/wx-chevalier/go-utils/certutils"
10 | "k8s.io/client-go/util/cert"
11 | )
12 |
13 | var _ = Describe("GenCert", func() {
14 | It("successfully generates a cert for the given config", func() {
15 | certs, err := GenerateSelfSignedCertificate(cert.Config{
16 | CommonName: "secure.af",
17 | Organization: []string{"solo.io"},
18 | AltNames: cert.AltNames{
19 | DNSNames: []string{
20 | "secure.af",
21 | "secure.af.svc",
22 | "secure.af.svc.cluster.local",
23 | },
24 | },
25 | Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
26 | })
27 | Expect(err).NotTo(HaveOccurred())
28 | Expect(len(certs.CaCertificate)).To(BeNumerically(">", 1))
29 | Expect(len(certs.ServerCertificate)).To(BeNumerically(">", 1))
30 | Expect(len(certs.ServerCertKey)).To(BeNumerically(">", 1))
31 | })
32 | })
33 |
--------------------------------------------------------------------------------
/builtinutils/builtinutil.go:
--------------------------------------------------------------------------------
1 | package builtinutil
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | )
7 |
8 | // CastInterfaceToInterfaceSlice ...
9 | func CastInterfaceToInterfaceSlice(slice interface{}) ([]interface{}, error) {
10 | s := reflect.ValueOf(slice)
11 | if s.Kind() != reflect.Slice {
12 | return []interface{}{}, fmt.Errorf("Input is not a slice: %#v", slice)
13 | }
14 |
15 | ret := make([]interface{}, s.Len())
16 |
17 | for i := 0; i < s.Len(); i++ {
18 | ret[i] = s.Index(i).Interface()
19 | }
20 |
21 | return ret, nil
22 | }
23 |
24 | // DeepEqualSlices ...
25 | func DeepEqualSlices(expected, actual []interface{}) bool {
26 | expectedMap := map[string]bool{}
27 | for _, itm := range expected {
28 | itmAsStr := fmt.Sprintf("%#v", itm)
29 | expectedMap[itmAsStr] = true
30 | }
31 | actualMap := map[string]bool{}
32 | for _, itm := range actual {
33 | itmAsStr := fmt.Sprintf("%#v", itm)
34 | actualMap[itmAsStr] = true
35 | }
36 | return reflect.DeepEqual(expectedMap, actualMap)
37 | }
38 |
--------------------------------------------------------------------------------
/slackutils/http.go:
--------------------------------------------------------------------------------
1 | package slackutils
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "encoding/json"
7 | "net/http"
8 |
9 | "github.com/wx-chevalier/go-utils/contextutils"
10 | "go.uber.org/zap"
11 | )
12 |
13 | type HttpClient interface {
14 | PostJsonContent(ctx context.Context, message, url string)
15 | }
16 |
17 | type DefaultHttpClient struct{}
18 |
19 | func (*DefaultHttpClient) PostJsonContent(ctx context.Context, message, url string) {
20 | type Payload struct {
21 | Text string `json:"text"`
22 | }
23 |
24 | data := Payload{
25 | Text: message,
26 | }
27 | payloadBytes, err := json.Marshal(data)
28 | if err != nil {
29 | contextutils.LoggerFrom(ctx).Errorw("Notifying slack failed", zap.Error(err))
30 | return
31 | }
32 | body := bytes.NewReader(payloadBytes)
33 |
34 | req, err := http.Post(url, "application/json", body)
35 | defer req.Body.Close()
36 | if err != nil {
37 | contextutils.LoggerFrom(ctx).Errorw("Notifying slack failed", zap.Error(err))
38 | return
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/versionutils/kubeapi/list_test.go:
--------------------------------------------------------------------------------
1 | package kubeapi_test
2 |
3 | import (
4 | "math/rand"
5 | "sort"
6 | "time"
7 |
8 | . "github.com/onsi/ginkgo"
9 | . "github.com/onsi/gomega"
10 | "github.com/wx-chevalier/go-utils/versionutils/kubeapi"
11 | )
12 |
13 | var _ = Describe("VersionList", func() {
14 | Describe("sort", func() {
15 | It("works", func() {
16 | orderedVersions := []string{"v1alpha1", "v1beta1", "v1beta2", "v1", "v2beta1", "v2beta2", "v4", "v5alpha2", "v5beta1"}
17 |
18 | subject := make(kubeapi.VersionList, 0, len(orderedVersions))
19 | for _, v := range orderedVersions {
20 | parsedVersion, err := kubeapi.ParseVersion(v)
21 | Expect(err).NotTo(HaveOccurred())
22 | subject = append(subject, parsedVersion)
23 | }
24 | rand.Seed(time.Now().UnixNano())
25 | rand.Shuffle(subject.Len(), subject.Swap)
26 |
27 | sort.Slice(subject, subject.Less)
28 |
29 | for i, apiVersion := range subject {
30 | Expect(apiVersion.String()).To(Equal(orderedVersions[i]))
31 | }
32 | })
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/testutils/clusterlock/clusterlock_suite_test.go:
--------------------------------------------------------------------------------
1 | package clusterlock_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/wx-chevalier/go-utils/testutils/clusterlock"
7 | "github.com/wx-chevalier/go-utils/testutils/kube"
8 | "github.com/wx-chevalier/go-utils/testutils/runners/consul"
9 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | "k8s.io/client-go/kubernetes"
11 |
12 | . "github.com/onsi/ginkgo"
13 | . "github.com/onsi/gomega"
14 | )
15 |
16 | func TestClusterlock(t *testing.T) {
17 | RegisterFailHandler(Fail)
18 | RunSpecs(t, "Clusterlock Suite")
19 | }
20 |
21 | var (
22 | consulFactory *consul.ConsulFactory
23 | kubeClient kubernetes.Interface
24 | )
25 |
26 | var _ = BeforeSuite(func() {
27 | kubeClient = kube.MustKubeClient()
28 | var err error
29 | consulFactory, err = consul.NewConsulFactory()
30 | Expect(err).NotTo(HaveOccurred())
31 | })
32 |
33 | var _ = AfterSuite(func() {
34 | _ = consulFactory.Clean()
35 | kubeClient.CoreV1().ConfigMaps("default").Delete(clusterlock.LockResourceName, &v1.DeleteOptions{})
36 | })
37 |
--------------------------------------------------------------------------------
/dockerutils/exec.go:
--------------------------------------------------------------------------------
1 | package docker
2 |
3 | import (
4 | "io"
5 | "os"
6 | "os/exec"
7 | )
8 |
9 | // containerCmd implements exec.Cmd for docker containers
10 | type containerCmd struct {
11 | nameOrID string // the container name or ID
12 | args []string
13 | env []string
14 | stdin io.Reader
15 | stdout io.Writer
16 | stderr io.Writer
17 | }
18 |
19 | func Command(args ...string) *containerCmd {
20 | return &containerCmd{
21 | args: args,
22 | stderr: os.Stderr,
23 | stdout: os.Stdout,
24 | }
25 | }
26 |
27 | func (c *containerCmd) Run() error {
28 | var args []string
29 |
30 | // set env
31 | for _, env := range c.env {
32 | args = append(args, "-e", env)
33 | }
34 | args = append(
35 | args,
36 | // finally, with the caller args
37 | c.args...,
38 | )
39 |
40 | cmd := exec.Command("docker", args...)
41 | if c.stdin != nil {
42 | cmd.Stdin = c.stdin
43 | }
44 | if c.stderr != nil {
45 | cmd.Stderr = c.stderr
46 | }
47 | if c.stdout != nil {
48 | cmd.Stdout = c.stdout
49 | }
50 | return cmd.Run()
51 | }
52 |
--------------------------------------------------------------------------------
/kubectrlutils/pod_termination.go:
--------------------------------------------------------------------------------
1 | package kubeutils
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/wx-chevalier/go-utils/log"
7 | )
8 |
9 | const (
10 | TERMINATION_LOG = "/dev/termination-log"
11 | )
12 |
13 | /*
14 | This function is in kubeutils because it is meant to only be used in containers deployed in kubernetes
15 |
16 | Upon termination kubernetes pods will read from a log file in the container and output the contents to
17 | the pod spec for debugging. https://kubernetes.io/docs/tasks/debug-application-cluster/determine-reason-pod-failure/
18 | */
19 |
20 | func LogFailureState(failureErr error) {
21 | file, err := os.OpenFile(TERMINATION_LOG, os.O_RDWR, 0)
22 | if err != nil {
23 | // termination log file does not exist - this can happen in non-kube environments so it is a no-op
24 | return
25 | }
26 | _, err = file.Write([]byte(failureErr.Error()))
27 | if err != nil {
28 | // we failed to write to termination log, this should never happen
29 | log.Fatalf("failed to write error %s due to %s", failureErr.Error(), err.Error())
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/maputils/maputil.go:
--------------------------------------------------------------------------------
1 | package maputil
2 |
3 | // KeysOfStringInterfaceMap ...
4 | func KeysOfStringInterfaceMap(m map[string]interface{}) []string {
5 | keys := make([]string, len(m))
6 |
7 | i := 0
8 | for k := range m {
9 | keys[i] = k
10 | i++
11 | }
12 |
13 | return keys
14 | }
15 |
16 | // KeysOfStringStringMap ...
17 | func KeysOfStringStringMap(m map[string]string) []string {
18 | keys := make([]string, len(m))
19 |
20 | i := 0
21 | for k := range m {
22 | keys[i] = k
23 | i++
24 | }
25 |
26 | return keys
27 | }
28 |
29 | // CloneStringStringMap ...
30 | func CloneStringStringMap(m map[string]string) map[string]string {
31 | cloneMap := map[string]string{}
32 | for k, v := range m {
33 | cloneMap[k] = v
34 | }
35 | return cloneMap
36 | }
37 |
38 | // MergeStringStringMap - returns a new map object,
39 | // DOES NOT modify either input map
40 | func MergeStringStringMap(m1, m2 map[string]string) map[string]string {
41 | mergedMap := CloneStringStringMap(m1)
42 | for k, v := range m2 {
43 | mergedMap[k] = v
44 | }
45 | return mergedMap
46 | }
47 |
--------------------------------------------------------------------------------
/manifestutils/README.md:
--------------------------------------------------------------------------------
1 | # Manifest Test Library
2 |
3 | This package contains some utils for easily parsing installation manifests (i.e. Helm-generated yaml files)
4 | and writing tests against those manifests. This is to ensure your Helm chart is properly linted and meets
5 | expectations.
6 |
7 | ## Usage
8 |
9 | - Define a test suite that parses a manifest, for example see `test/example_suite_test.go`.
10 | - Define a test file that tests the manifest, for example see `test/example_test.go`.
11 |
12 | These tests should be very concise based on the resource builder utilities provided.
13 |
14 | ## Future
15 |
16 | In the short term, the goal is increasing test coverage of helm charts that are published by different
17 | projects. Some useful extensions in the future would include:
18 |
19 | - Extra utilities for helping test helm charts with different values overrides.
20 |
21 | It may make sense to turn this into a Helm chart generator in the future, to the extent that process can be
22 | simplified (see `github.com/wx-chevalier/build` for more info about the Solo common build SDK).
--------------------------------------------------------------------------------
/logutils/log_test.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "bytes"
5 | "regexp"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestSetOutWriter(t *testing.T) {
12 | var b bytes.Buffer
13 | SetOutWriter(&b)
14 | Printf("test %s", "log")
15 | require.Equal(t, "test log\n", b.String())
16 | }
17 |
18 | func TestSetEnableDebugLog(t *testing.T) {
19 | t.Log("enable debug log")
20 | {
21 | SetEnableDebugLog(true)
22 | var b bytes.Buffer
23 | SetOutWriter(&b)
24 | Debugf("test %s", "log")
25 | require.Equal(t, "\x1b[35;1mtest log\x1b[0m\n", b.String())
26 | }
27 |
28 | t.Log("disable debug log")
29 | {
30 | SetEnableDebugLog(false)
31 | var b bytes.Buffer
32 | SetOutWriter(&b)
33 | Debugf("test %s", "log")
34 | require.Equal(t, "", b.String())
35 | }
36 | }
37 |
38 | func TestSetTimestampLayout(t *testing.T) {
39 | var b bytes.Buffer
40 | SetOutWriter(&b)
41 | SetTimestampLayout("15-04-05")
42 | TPrintf("test %s", "log")
43 | re := regexp.MustCompile(`\[.+-.+-.+\] test log`)
44 | require.True(t, re.MatchString(b.String()), b.String())
45 | }
46 |
--------------------------------------------------------------------------------
/testutils/helper/http_echo.go:
--------------------------------------------------------------------------------
1 | package helper
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type echoPod struct {
8 | *testContainer
9 | }
10 |
11 | func (t *echoPod) Deploy(timeout time.Duration) error {
12 | return t.deploy(timeout)
13 | }
14 |
15 | const (
16 | defaultHttpEchoImage = "kennship/http-echo:latest"
17 | HttpEchoName = "http-echo"
18 | HttpEchoPort = 3000
19 | )
20 |
21 | func NewEchoHttp(namespace string) (*echoPod, error) {
22 | container, err := newTestContainer(namespace, defaultHttpEchoImage, HttpEchoName, HttpEchoPort)
23 | if err != nil {
24 | return nil, err
25 | }
26 | return &echoPod{
27 | testContainer: container,
28 | }, nil
29 | }
30 |
31 | const (
32 | defaultTcpEchoImage = "soloio/tcp-echo:latest"
33 | TcpEchoName = "tcp-echo"
34 | TcpEchoPort = 1025
35 | )
36 |
37 | func NewEchoTcp(namespace string) (*echoPod, error) {
38 | container, err := newTestContainer(namespace, defaultTcpEchoImage, TcpEchoName, TcpEchoPort)
39 | if err != nil {
40 | return nil, err
41 | }
42 | return &echoPod{
43 | testContainer: container,
44 | }, nil
45 | }
46 |
--------------------------------------------------------------------------------
/logutils/severity.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import "github.com/wx-chevalier/go-utils/colorstring"
4 |
5 | // Severity ...
6 | type Severity uint8
7 |
8 | const (
9 | errorSeverity Severity = iota
10 | warnSeverity
11 | normalSeverity
12 | infoSeverity
13 | successSeverity
14 | debugSeverity
15 | )
16 |
17 | type severityColorFunc colorstring.ColorfFunc
18 |
19 | var (
20 | successSeverityColorFunc severityColorFunc = colorstring.Greenf
21 | infoSeverityColorFunc severityColorFunc = colorstring.Bluef
22 | normalSeverityColorFunc severityColorFunc = colorstring.NoColorf
23 | debugSeverityColorFunc severityColorFunc = colorstring.Magentaf
24 | warnSeverityColorFunc severityColorFunc = colorstring.Yellowf
25 | errorSeverityColorFunc severityColorFunc = colorstring.Redf
26 | )
27 |
28 | var severityColorFuncMap = map[Severity]severityColorFunc{
29 | successSeverity: successSeverityColorFunc,
30 | infoSeverity: infoSeverityColorFunc,
31 | normalSeverity: normalSeverityColorFunc,
32 | debugSeverity: debugSeverityColorFunc,
33 | warnSeverity: warnSeverityColorFunc,
34 | errorSeverity: errorSeverityColorFunc,
35 | }
36 |
--------------------------------------------------------------------------------
/wmanager/README.md:
--------------------------------------------------------------------------------
1 | # wmanager
2 |
3 | manage worker in golang, provide start, stop, pname method for worker.
4 |
5 | wmanager add trycatch wrapper for each worker.
6 |
7 | ## Usage
8 |
9 | ### 1. Your method implements this interface
10 |
11 | ```go
12 | type Worker interface {
13 | Start() // block mode
14 | Stop() // only call worker ctx cancel
15 | Pname() string // worker process name
16 | Status() int // worker status
17 | }
18 | ```
19 |
20 | ### 2. new woker manager, add worker
21 |
22 | ```go
23 | wm = wmanager.NewWorkerManager()
24 |
25 | // server
26 | wm.AddWorker(master.NewAPIServer(ctx))
27 | wm.AddWorker(master.NewServer(ctx))
28 |
29 | // worker
30 | wm.AddWorker(master.NewHrkeScheduler(ctx))
31 | wm.AddWorker(master.NewCollector(ctx))
32 | ```
33 |
34 | ### 3. start workers
35 |
36 | ```go
37 | wm.Start()
38 | ```
39 |
40 | ### 4. stop workers
41 |
42 | ```golang
43 | wm.Stop()
44 | ```
45 |
46 | ### 5. stop workers
47 |
48 | ```golang
49 | wm.Stop()
50 | ```
51 |
52 | ### 6. wait for all worker exit
53 |
54 | ```golang
55 | wm.Wait()
56 |
57 | or
58 |
59 | wm.WaitTimeout(N)
60 | ```
61 |
--------------------------------------------------------------------------------
/vfsutils/mount_test.go:
--------------------------------------------------------------------------------
1 | package vfsutils_test
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/wx-chevalier/go-utils/githubutils"
7 | "github.com/wx-chevalier/go-utils/vfsutils"
8 |
9 | . "github.com/onsi/ginkgo"
10 | . "github.com/onsi/gomega"
11 | )
12 |
13 | var _ = Describe("mounted repo utils", func() {
14 |
15 | const (
16 | owner = "wx-chevalier"
17 | repo = "testrepo"
18 | sha = "9065a9a84e286ea7f067f4fc240944b0a4d4c82a"
19 | )
20 |
21 | var (
22 | ctx = context.Background()
23 | mountedRepo vfsutils.MountedRepo
24 | )
25 |
26 | BeforeEach(func() {
27 | client, err := githubutils.GetClient(ctx)
28 | Expect(err).NotTo(HaveOccurred())
29 | mountedRepo = vfsutils.NewLazilyMountedRepo(client, owner, repo, sha)
30 | })
31 |
32 | It("can get contents", func() {
33 | contents, err := mountedRepo.GetFileContents(ctx, "tmp.txt")
34 | Expect(err).NotTo(HaveOccurred())
35 | Expect(string(contents)).To(ContainSubstring("another"))
36 | })
37 |
38 | It("can list files", func() {
39 | files, err := mountedRepo.ListFiles(ctx, "namespace")
40 | Expect(err).NotTo(HaveOccurred())
41 | Expect(len(files)).To(Equal(1))
42 | })
43 |
44 | })
45 |
--------------------------------------------------------------------------------
/funcutils/retry.go:
--------------------------------------------------------------------------------
1 | package retry
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | // Action ...
9 | type Action func(attempt uint) error
10 |
11 | // Model ...
12 | type Model struct {
13 | retry uint
14 | waitTime time.Duration
15 | }
16 |
17 | // Times ...
18 | func Times(retry uint) *Model {
19 | Model := Model{}
20 | return Model.Times(retry)
21 | }
22 |
23 | // Times ...
24 | func (Model *Model) Times(retry uint) *Model {
25 | Model.retry = retry
26 | return Model
27 | }
28 |
29 | // Wait ...
30 | func Wait(waitTime time.Duration) *Model {
31 | Model := Model{}
32 | return Model.Wait(waitTime)
33 | }
34 |
35 | // Wait ...
36 | func (Model *Model) Wait(waitTime time.Duration) *Model {
37 | Model.waitTime = waitTime
38 | return Model
39 | }
40 |
41 | // Try ...
42 | func (Model Model) Try(action Action) error {
43 | if action == nil {
44 | return fmt.Errorf("no action specified")
45 | }
46 |
47 | var err error
48 | for attempt := uint(0); (0 == attempt || nil != err) && attempt <= Model.retry; attempt++ {
49 | if attempt > 0 && Model.waitTime > 0 {
50 | time.Sleep(Model.waitTime)
51 | }
52 |
53 | err = action(attempt)
54 | }
55 |
56 | return err
57 | }
58 |
--------------------------------------------------------------------------------
/botutils/interface.go:
--------------------------------------------------------------------------------
1 | package botutils
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/google/go-github/github"
7 | )
8 |
9 | type Plugin interface {
10 | }
11 |
12 | type PullRequestHandler interface {
13 | Plugin
14 | HandlePREvent(ctx context.Context, client *github.Client, event *github.PullRequestEvent) error
15 | }
16 |
17 | type PullRequestReviewHandler interface {
18 | Plugin
19 | HandlePullRequestReviewEvent(ctx context.Context, client *github.Client, event *github.PullRequestReviewEvent) error
20 | }
21 |
22 | type IssueCommentHandler interface {
23 | Plugin
24 | HandleIssueCommentEvent(ctx context.Context, client *github.Client, event *github.IssueCommentEvent) error
25 | }
26 |
27 | type CommitCommentHandler interface {
28 | Plugin
29 | HandleCommitCommentEvent(ctx context.Context, client *github.Client, event *github.CommitCommentEvent) error
30 | }
31 |
32 | type ReleaseHandler interface {
33 | Plugin
34 | HandleReleaseEvent(ctx context.Context, client *github.Client, event *github.ReleaseEvent) error
35 | }
36 |
37 | type IssuesHandler interface {
38 | Plugin
39 | HandleIssuesEvent(ctx context.Context, client *github.Client, event *github.IssuesEvent) error
40 | }
41 |
--------------------------------------------------------------------------------
/commandutils/command_test.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestNewCommandSlice(t *testing.T) {
10 | t.Log("it fails if slice empty")
11 | {
12 | cmd, err := NewFromSlice([]string{})
13 | require.Error(t, err)
14 | require.Equal(t, (*Model)(nil), cmd)
15 | }
16 |
17 | t.Log("it creates cmd if cmdSlice has 1 element")
18 | {
19 | _, err := NewFromSlice([]string{"ls"})
20 | require.NoError(t, err)
21 | }
22 |
23 | t.Log("it creates cmd if cmdSlice has multiple elements")
24 | {
25 | _, err := NewFromSlice([]string{"ls", "-a", "-l", "-h"})
26 | require.NoError(t, err)
27 | }
28 | }
29 |
30 | func TestNewWithParams(t *testing.T) {
31 | t.Log("it fails if params empty")
32 | {
33 | cmd, err := NewWithParams()
34 | require.Error(t, err)
35 | require.Equal(t, (*Model)(nil), cmd)
36 | }
37 |
38 | t.Log("it creates cmd if params has 1 element")
39 | {
40 | _, err := NewWithParams("ls")
41 | require.NoError(t, err)
42 | }
43 |
44 | t.Log("it creates cmd if params has multiple elements")
45 | {
46 | _, err := NewWithParams("ls", "-a", "-l", "-h")
47 | require.NoError(t, err)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/healthutils/grpc.go:
--------------------------------------------------------------------------------
1 | package healthchecker
2 |
3 | import (
4 | "os"
5 | "os/signal"
6 | "sync/atomic"
7 | "syscall"
8 |
9 | "google.golang.org/grpc/health"
10 | healthpb "google.golang.org/grpc/health/grpc_health_v1"
11 | )
12 |
13 | type grpcHealthChecker struct {
14 | srv *health.Server
15 | ok uint32
16 | name string
17 | }
18 |
19 | var _ HealthChecker = new(grpcHealthChecker)
20 |
21 | func NewGrpc(serviceName string, grpcHealthServer *health.Server) *grpcHealthChecker {
22 | hc := &grpcHealthChecker{}
23 | hc.ok = 1
24 | hc.name = serviceName
25 |
26 | hc.srv = grpcHealthServer
27 | hc.srv.SetServingStatus(serviceName, healthpb.HealthCheckResponse_SERVING)
28 |
29 | sigterm := make(chan os.Signal, 1)
30 | signal.Notify(sigterm, syscall.SIGTERM)
31 |
32 | go func() {
33 | <-sigterm
34 | atomic.StoreUint32(&hc.ok, 0)
35 | hc.srv.SetServingStatus(serviceName, healthpb.HealthCheckResponse_NOT_SERVING)
36 | }()
37 |
38 | return hc
39 | }
40 |
41 | func (hc *grpcHealthChecker) Fail() {
42 | atomic.StoreUint32(&hc.ok, 0)
43 | hc.srv.SetServingStatus(hc.name, healthpb.HealthCheckResponse_NOT_SERVING)
44 | }
45 |
46 | func (hc *grpcHealthChecker) GetServer() *health.Server {
47 | return hc.srv
48 | }
49 |
--------------------------------------------------------------------------------
/kubectrlutils/wait_crd.go:
--------------------------------------------------------------------------------
1 | package kubeutils
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/avast/retry-go"
7 | "github.com/wx-chevalier/go-utils/errutils"
8 | "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
9 | apiexts "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11 | )
12 |
13 | // Waits for a CRD to be "established" in kubernetes, which means it's active an can be
14 | // CRUD'ed by clients
15 | func WaitForCrdActive(apiexts apiexts.Interface, crdName string) error {
16 | return retry.Do(func() error {
17 | crd, err := apiexts.ApiextensionsV1beta1().CustomResourceDefinitions().Get(crdName, metav1.GetOptions{})
18 | if err != nil {
19 | return errors.Wrapf(err, "lookup crd %v", crdName)
20 | }
21 |
22 | var established bool
23 | for _, status := range crd.Status.Conditions {
24 | if status.Type == v1beta1.Established {
25 | established = true
26 | break
27 | }
28 | }
29 |
30 | if !established {
31 | return errors.Errorf("crd %v exists but not yet established by kube", crdName)
32 | }
33 |
34 | return nil
35 | },
36 | retry.Delay(time.Millisecond*500),
37 | retry.DelayType(retry.FixedDelay),
38 | )
39 | }
40 |
--------------------------------------------------------------------------------
/strutils/text.go:
--------------------------------------------------------------------------------
1 | package stringutil
2 |
3 | import (
4 | "bufio"
5 | "math"
6 | "strings"
7 | )
8 |
9 | // IndentTextWithMaxLength ...
10 | func IndentTextWithMaxLength(text, indent string, maxTextLineCharWidth int, isIndentFirstLine bool) string {
11 | if maxTextLineCharWidth < 1 {
12 | return ""
13 | }
14 |
15 | formattedText := ""
16 |
17 | addLine := func(line string) {
18 | isFirstLine := (formattedText == "")
19 | if isFirstLine && !isIndentFirstLine {
20 | formattedText = line
21 | } else {
22 | if !isFirstLine {
23 | formattedText += "\n"
24 | }
25 | formattedText += indent + line
26 | }
27 | }
28 |
29 | scanner := bufio.NewScanner(strings.NewReader(text))
30 | for scanner.Scan() {
31 | line := scanner.Text()
32 | lineLength := len(line)
33 | if lineLength > maxTextLineCharWidth {
34 | lineCnt := math.Ceil(float64(lineLength) / float64(maxTextLineCharWidth))
35 | for i := 0; i < int(lineCnt); i++ {
36 | startIdx := i * maxTextLineCharWidth
37 | endIdx := startIdx + maxTextLineCharWidth
38 | if endIdx > lineLength {
39 | endIdx = lineLength
40 | }
41 | addLine(line[startIdx:endIdx])
42 | }
43 | } else {
44 | addLine(line)
45 | }
46 | }
47 |
48 | return formattedText
49 | }
50 |
--------------------------------------------------------------------------------
/kubeinstallutils/kubeinstall/mocks/mock_kube_installer.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/wx-chevalier/go-utils/installutils/kubeinstall"
7 | "github.com/wx-chevalier/go-utils/installutils/kuberesource"
8 | )
9 |
10 | type MockKubeInstaller struct {
11 | ReconcileCalledWith ReconcileParams
12 | PurgeCalledWith PurgeParams
13 | ReturnErr error
14 | }
15 |
16 | type ReconcileParams struct {
17 | InstallNamespace string
18 | Resources kuberesource.UnstructuredResources
19 | InstallLabels map[string]string
20 | }
21 |
22 | type PurgeParams struct {
23 | InstallLabels map[string]string
24 | }
25 |
26 | func (i *MockKubeInstaller) ReconcileResources(ctx context.Context, params kubeinstall.ReconcileParams) error {
27 | i.ReconcileCalledWith = ReconcileParams{params.InstallNamespace, params.Resources, params.OwnerLabels}
28 | return i.ReturnErr
29 | }
30 |
31 | func (i *MockKubeInstaller) PurgeResources(ctx context.Context, withLabels map[string]string) error {
32 | i.PurgeCalledWith = PurgeParams{withLabels}
33 | return i.ReturnErr
34 | }
35 |
36 | func (i *MockKubeInstaller) ListAllResources(ctx context.Context) kuberesource.UnstructuredResources {
37 | return i.ReconcileCalledWith.Resources
38 | }
39 |
--------------------------------------------------------------------------------
/testutils/assertions.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "github.com/gogo/protobuf/proto"
5 | . "github.com/onsi/gomega"
6 | )
7 |
8 | // ExpectEqualProtoMessages provides richer error messages than struct comparison by leveraging the String() method that all
9 | // proto Messages provide. On error, Gomega's string comparison utility prints a few characters of the text immediately
10 | // surrounding the first discrepancy.
11 | //
12 | // Variadic optionalDescription argument is passed on to fmt.Sprintf() and is used to annotate failure messages.
13 | //
14 | // Example of the output:
15 | // optionalDescription is rendered here: template string with values foo and bar
16 | // Expected
17 | // : "...-1010" vers..."
18 | // to equal |
19 | // : "...-10101" ver..."
20 | func ExpectEqualProtoMessages(a, b proto.Message, optionalDescription ...interface{}) {
21 | if proto.Equal(a, b) {
22 | return
23 | }
24 | // One shortcoming is that you only get +/- 5 chars of context
25 | // per: https://github.com/onsi/gomega/blob/master/format/format.go#L146
26 | // TODO(mitchdraft) gomega pr to modify charactersAroundMismatchToInclude (if not merged will make a util)
27 | Expect(a.String()).To(Equal(b.String()), optionalDescription...)
28 | }
29 |
--------------------------------------------------------------------------------
/testutils/deploy_testrunner.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "k8s.io/client-go/rest"
5 | )
6 |
7 | // Deprecated: no one calls this
8 | func DeployTestRunner(cfg *rest.Config, namespace string) error {
9 | return DeployFromYaml(cfg, namespace, TestRunnerYaml)
10 | }
11 |
12 | const TestRunnerYaml = `
13 | apiVersion: v1
14 | kind: Pod
15 | metadata:
16 | labels:
17 | gloo: testrunner
18 | name: testrunner
19 | spec:
20 | containers:
21 | - image: soloio/testrunner:testing-8671e8b9
22 | imagePullPolicy: IfNotPresent
23 | command:
24 | - sleep
25 | - "36000"
26 | name: testrunner
27 | restartPolicy: Always`
28 |
29 | const NginxYaml = `
30 | apiVersion: apps/v1
31 | kind: Deployment
32 | metadata:
33 | name: nginx-deployment
34 | spec:
35 | selector:
36 | matchLabels:
37 | app: nginx
38 | replicas: 2
39 | template:
40 | metadata:
41 | labels:
42 | app: nginx
43 | spec:
44 | containers:
45 | - name: nginx
46 | image: nginx:1.7.9
47 | ports:
48 | - containerPort: 80
49 | ---
50 | apiVersion: v1
51 | kind: Service
52 | metadata:
53 | name: nginx
54 | labels:
55 | app: nginx
56 | spec:
57 | ports:
58 | - port: 80
59 | name: http
60 | selector:
61 | app: nginx
62 | `
63 |
--------------------------------------------------------------------------------
/kubectrlutils/namespaces.go:
--------------------------------------------------------------------------------
1 | package kubeutils
2 |
3 | import (
4 | "golang.org/x/sync/errgroup"
5 | v1 "k8s.io/api/core/v1"
6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7 | "k8s.io/client-go/kubernetes"
8 | )
9 |
10 | func CreateNamespacesInParallel(kube kubernetes.Interface, namespaces ...string) error {
11 | eg := errgroup.Group{}
12 | for _, namespace := range namespaces {
13 | namespace := namespace
14 | eg.Go(func() error {
15 | _, err := kube.CoreV1().Namespaces().Create(&v1.Namespace{
16 | ObjectMeta: metav1.ObjectMeta{
17 | Name: namespace,
18 | },
19 | })
20 | return err
21 | })
22 | }
23 | return eg.Wait()
24 | }
25 |
26 | func DeleteNamespacesInParallelBlocking(kube kubernetes.Interface, namespaces ...string) error {
27 | eg := errgroup.Group{}
28 | for _, namespace := range namespaces {
29 | namespace := namespace
30 | eg.Go(func() error {
31 | return kube.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{})
32 | })
33 | }
34 | return eg.Wait()
35 | }
36 |
37 | func DeleteNamespacesInParallel(kube kubernetes.Interface, namespaces ...string) {
38 | for _, namespace := range namespaces {
39 | namespace := namespace
40 | go func() {
41 | kube.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{})
42 | }()
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/envutils/vars.go:
--------------------------------------------------------------------------------
1 | package envutils
2 |
3 | import (
4 | "context"
5 | "os"
6 | "strconv"
7 |
8 | "go.uber.org/zap"
9 |
10 | "github.com/wx-chevalier/go-utils/contextutils"
11 | )
12 |
13 | func MustGetPodNamespace(ctx context.Context) string {
14 | contextutils.LoggerFrom(ctx).Infow("Looking for install namespace in POD_NAMESPACE environment variable")
15 | namespace := os.Getenv("POD_NAMESPACE")
16 | if namespace == "" {
17 | contextutils.LoggerFrom(ctx).Fatalw("Could not determine namespace, must have non-empty POD_NAMESPACE in environment")
18 | }
19 | contextutils.LoggerFrom(ctx).Infow("Found install namespace", zap.String("installNamespace", namespace))
20 | return namespace
21 | }
22 |
23 | func MustGetGrpcPort(ctx context.Context) int {
24 | contextutils.LoggerFrom(ctx).Infow("Looking for grpc port in GRPC_PORT environment variable")
25 | port := os.Getenv("GRPC_PORT")
26 | if port == "" {
27 | contextutils.LoggerFrom(ctx).Fatalw("Could not determine port, must have non-empty GRPC_PORT in environment")
28 | }
29 | p, err := strconv.Atoi(port)
30 | if err != nil {
31 | contextutils.LoggerFrom(ctx).Fatalw("Failed to parse grpc port",
32 | zap.Error(err),
33 | zap.String("port", port))
34 | }
35 | contextutils.LoggerFrom(ctx).Infow("Found grpc port", zap.Int("grpcPort", p))
36 | return p
37 | }
38 |
--------------------------------------------------------------------------------
/strutils/strings.go:
--------------------------------------------------------------------------------
1 | package stringutils
2 |
3 | import (
4 | "reflect"
5 | "sort"
6 | )
7 |
8 | func ContainsString(s string, slice []string) bool {
9 | for _, s2 := range slice {
10 | if s2 == s {
11 | return true
12 | }
13 | }
14 | return false
15 | }
16 |
17 | // Returns true if slice strings contains any of the strings.
18 | func ContainsAny(strings []string, slice []string) bool {
19 | for _, s := range strings {
20 | if ContainsString(s, slice) {
21 | return true
22 | }
23 | }
24 | return false
25 | }
26 |
27 | func ContainsMap(maps []map[string]string, item map[string]string) bool {
28 | for _, m := range maps {
29 | if reflect.DeepEqual(m, item) {
30 | return true
31 | }
32 | }
33 | return false
34 | }
35 |
36 | func KeysAndValues(m map[string]string) ([]string, []string) {
37 | var keys []string
38 | for k := range m {
39 | keys = append(keys, k)
40 | }
41 | sort.Strings(keys)
42 | var values []string
43 | for _, k := range keys {
44 | values = append(values, m[k])
45 | }
46 | return keys, values
47 | }
48 |
49 | func Unique(stringSlice []string) []string {
50 | keys := make(map[string]bool)
51 | list := []string{}
52 | for _, entry := range stringSlice {
53 | if _, value := keys[entry]; !value {
54 | keys[entry] = true
55 | list = append(list, entry)
56 | }
57 | }
58 | return list
59 | }
60 |
--------------------------------------------------------------------------------
/progressutils/wrapper.go:
--------------------------------------------------------------------------------
1 | package progress
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strings"
7 |
8 | "golang.org/x/crypto/ssh/terminal"
9 | )
10 |
11 | // Wrapper ...
12 | type Wrapper struct {
13 | spinner Spinner
14 | action func()
15 | interactiveMode bool
16 | }
17 |
18 | // NewWrapper ...
19 | func NewWrapper(spinner Spinner, interactiveMode bool) Wrapper {
20 | return Wrapper{
21 | spinner: spinner,
22 | interactiveMode: interactiveMode,
23 | }
24 | }
25 |
26 | // NewDefaultWrapper ...
27 | func NewDefaultWrapper(message string) Wrapper {
28 | spinner := NewDefaultSpinner(message)
29 | interactiveMode := OutputDeviceIsTerminal()
30 | return NewWrapper(spinner, interactiveMode)
31 | }
32 |
33 | // WrapAction ...
34 | func (w Wrapper) WrapAction(action func()) {
35 | if w.interactiveMode {
36 | w.spinner.Start()
37 | action()
38 | w.spinner.Stop()
39 | } else {
40 | message := w.spinner.message
41 | if !strings.HasSuffix(message, ".") {
42 | message = message + "..."
43 | }
44 | if _, err := fmt.Fprintln(w.spinner.writer, message); err != nil {
45 | fmt.Printf("failed to print message: %s, error: %s", message, err)
46 | }
47 | action()
48 | }
49 | }
50 |
51 | // OutputDeviceIsTerminal ...
52 | func OutputDeviceIsTerminal() bool {
53 | return terminal.IsTerminal(int(os.Stdout.Fd()))
54 | }
55 |
--------------------------------------------------------------------------------
/testutils/exec/cmd.go:
--------------------------------------------------------------------------------
1 | package exec
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | "os"
7 | "os/exec"
8 |
9 | "github.com/onsi/ginkgo"
10 | "github.com/wx-chevalier/go-utils/errutils"
11 | )
12 |
13 | func RunCommand(workingDir string, verbose bool, args ...string) error {
14 | _, err := RunCommandOutput(workingDir, verbose, args...)
15 | return err
16 | }
17 |
18 | func RunCommandOutput(workingDir string, verbose bool, args ...string) (string, error) {
19 | return RunCommandInputOutput("", workingDir, verbose, args...)
20 | }
21 |
22 | func RunCommandInput(input, workingDir string, verbose bool, args ...string) error {
23 | _, err := RunCommandInputOutput(input, workingDir, verbose, args...)
24 | return err
25 | }
26 |
27 | func RunCommandInputOutput(input, workingDir string, verbose bool, args ...string) (string, error) {
28 | cmd := exec.Command(args[0], args[1:]...)
29 | cmd.Dir = workingDir
30 | cmd.Env = os.Environ()
31 | if len(input) > 0 {
32 | cmd.Stdin = bytes.NewBuffer([]byte(input))
33 | }
34 | buf := &bytes.Buffer{}
35 | var out io.Writer
36 | if verbose {
37 | out = io.MultiWriter(buf, ginkgo.GinkgoWriter)
38 | } else {
39 | out = buf
40 | }
41 | cmd.Stdout = out
42 | cmd.Stderr = out
43 | if err := cmd.Run(); err != nil {
44 | return "", errors.Wrapf(err, "%v failed: %s", cmd.Args, buf.String())
45 | }
46 |
47 | return buf.String(), nil
48 | }
49 |
--------------------------------------------------------------------------------
/testutils/testutil.go:
--------------------------------------------------------------------------------
1 | package testutil
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/wx-chevalier/go-utils/builtinutil"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | // EqualAndNoError ...
12 | func EqualAndNoError(t *testing.T, expected, actual interface{}, err error, msgAndArgs ...interface{}) {
13 | require.NoError(t, err, msgAndArgs...)
14 | require.Equal(t, expected, actual, msgAndArgs...)
15 | }
16 |
17 | func equalSlicesWithoutOrder(t *testing.T, expected, actual []interface{}, msgAndArgs ...interface{}) {
18 | if !builtinutil.DeepEqualSlices(expected, actual) {
19 | require.FailNow(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
20 | " != %#v (actual)", expected, actual), msgAndArgs...)
21 | }
22 | }
23 |
24 | // EqualSlicesWithoutOrder - regardless the order, but same items
25 | func EqualSlicesWithoutOrder(t *testing.T, expected, actual interface{}, msgAndArgs ...interface{}) {
26 | castedExpected, err := builtinutil.CastInterfaceToInterfaceSlice(expected)
27 | if err != nil {
28 | require.FailNow(t, fmt.Sprintf("'expected' is not a slice: %#v", expected), msgAndArgs...)
29 | }
30 |
31 | castedActual, err := builtinutil.CastInterfaceToInterfaceSlice(actual)
32 | if err != nil {
33 | require.FailNow(t, fmt.Sprintf("'actual' is not a slice: %#v", actual), msgAndArgs...)
34 | }
35 |
36 | equalSlicesWithoutOrder(t, castedExpected, castedActual, msgAndArgs...)
37 | }
38 |
--------------------------------------------------------------------------------
/logutils/log.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | "regexp"
8 | "runtime"
9 | "time"
10 |
11 | "github.com/k0kubun/pp"
12 | )
13 |
14 | var debugMode = os.Getenv("DEBUG") == "1"
15 | var DefaultOut io.Writer = os.Stdout
16 |
17 | func init() {
18 | if os.Getenv("DISABLE_COLOR") == "1" {
19 | pp.ColoringEnabled = false
20 | }
21 | }
22 |
23 | var rxp = regexp.MustCompile(".*/src/")
24 |
25 | func Sprintf(format string, a ...interface{}) string {
26 | return pp.Sprintf("%v\t"+format, append([]interface{}{line()}, a...)...)
27 | }
28 |
29 | func GreyPrintf(format string, a ...interface{}) {
30 | fmt.Fprintf(DefaultOut, "%v\t"+format+"\n", append([]interface{}{line()}, a...)...)
31 | }
32 |
33 | func Printf(format string, a ...interface{}) {
34 | fmt.Fprintln(DefaultOut, Sprintf(format, a...))
35 | }
36 |
37 | func Warnf(format string, a ...interface{}) {
38 | fmt.Fprintln(DefaultOut, Sprintf("WARNING:\n"+format+"\n", a...))
39 | }
40 |
41 | func Debugf(format string, a ...interface{}) {
42 | if debugMode {
43 | fmt.Fprintln(DefaultOut, Sprintf(format, a...))
44 | }
45 | }
46 |
47 | func Fatalf(format string, a ...interface{}) {
48 | fmt.Fprintln(DefaultOut, Sprintf(format, a...))
49 | os.Exit(1)
50 | }
51 |
52 | func line() string {
53 | _, file, line, _ := runtime.Caller(3)
54 | file = rxp.ReplaceAllString(file, "")
55 | return fmt.Sprintf("%v: %v:%v", time.Now().Format(time.RFC1123), file, line)
56 | }
57 |
--------------------------------------------------------------------------------
/pkcs12utils/README.md:
--------------------------------------------------------------------------------
1 | # package pkcs12
2 |
3 | [](https://godoc.org/software.sslmate.com/src/go-pkcs12)
4 |
5 | import "software.sslmate.com/src/go-pkcs12"
6 |
7 | Package pkcs12 implements some of PKCS#12 (also known as P12 or PFX).
8 | It is intended for decoding P12/PFX files for use with the `crypto/tls`
9 | package, and for encoding P12/PFX files for use by legacy applications which
10 | do not support newer formats. Since PKCS#12 uses weak encryption
11 | primitives, it SHOULD NOT be used for new applications.
12 |
13 | This package is forked from `golang.org/x/crypto/pkcs12`, which is frozen.
14 | The implementation is distilled from https://tools.ietf.org/html/rfc7292
15 | and referenced documents.
16 |
17 | This repository holds supplementary Go cryptography libraries.
18 |
19 | ## Import Path
20 |
21 | Note that although the source code and issue tracker for this package are hosted
22 | on GitHub, the import path is:
23 |
24 | software.sslmate.com/src/go-pkcs12
25 |
26 | Please be sure to use this path when you `go get` and `import` this package.
27 |
28 | ## Download/Install
29 |
30 | The easiest way to install is to run `go get -u software.sslmate.com/src/go-pkcs12`. You
31 | can also manually git clone the repository to `$GOPATH/src/software.sslmate.com/src/go-pkcs12`.
32 |
33 | ## Report Issues / Send Patches
34 |
35 | Open an issue or PR at https://github.com/SSLMate/go-pkcs12
36 |
--------------------------------------------------------------------------------
/contextutils/errors_and_logging.go:
--------------------------------------------------------------------------------
1 | package contextutils
2 |
3 | import (
4 | "context"
5 |
6 | "go.uber.org/zap"
7 | )
8 |
9 | func SilenceLogger(ctx context.Context) context.Context {
10 | return withLogger(ctx, zap.NewNop().Sugar())
11 | }
12 |
13 | func WithLogger(ctx context.Context, name string) context.Context {
14 | return withLogger(ctx, fromContext(ctx).Named(name))
15 | }
16 |
17 | func WithLoggerValues(ctx context.Context, meta ...interface{}) context.Context {
18 | return withLogger(ctx, fromContext(ctx).With(meta...))
19 | }
20 |
21 | func LoggerFrom(ctx context.Context) *zap.SugaredLogger {
22 | return fromContext(ctx)
23 | }
24 |
25 | type ErrorHandler interface {
26 | HandleErr(error)
27 | }
28 |
29 | type ErrorLogger struct {
30 | ctx context.Context
31 | }
32 |
33 | func (h *ErrorLogger) HandleErr(err error) {
34 | if err == nil {
35 | return
36 | }
37 | fromContext(h.ctx).Errorf(err.Error())
38 | }
39 |
40 | type errorHandlerKey struct{}
41 |
42 | func WithErrorHandler(ctx context.Context, errorHandler ErrorHandler) context.Context {
43 | return context.WithValue(ctx, errorHandlerKey{}, errorHandler)
44 | }
45 |
46 | func ErrorHandlerFrom(ctx context.Context) ErrorHandler {
47 | val := ctx.Value(errorHandlerKey{})
48 | if val == nil {
49 | return &ErrorLogger{
50 | ctx: ctx,
51 | }
52 | }
53 | errorHandler, ok := val.(ErrorHandler)
54 | if !ok {
55 | return &ErrorLogger{
56 | ctx: ctx,
57 | }
58 | }
59 | return errorHandler
60 | }
61 |
--------------------------------------------------------------------------------
/pkcs12utils/pbkdf_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package pkcs12
6 |
7 | import (
8 | "bytes"
9 | "testing"
10 | )
11 |
12 | func TestThatPBKDFWorksCorrectlyForLongKeys(t *testing.T) {
13 | cipherInfo := shaWithTripleDESCBC{}
14 |
15 | salt := []byte("\xff\xff\xff\xff\xff\xff\xff\xff")
16 | password, _ := bmpString("sesame")
17 | key := cipherInfo.deriveKey(salt, password, 2048)
18 |
19 | if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); bytes.Compare(key, expected) != 0 {
20 | t.Fatalf("expected key '%x', but found '%x'", expected, key)
21 | }
22 | }
23 |
24 | func TestThatPBKDFHandlesLeadingZeros(t *testing.T) {
25 | // This test triggers a case where I_j (in step 6C) ends up with leading zero
26 | // byte, meaning that len(Ijb) < v (leading zeros get stripped by big.Int).
27 | // This was previously causing bug whereby certain inputs would break the
28 | // derivation and produce the wrong output.
29 | key := pbkdf(sha1Sum, 20, 64, []byte("\xf3\x7e\x05\xb5\x18\x32\x4b\x4b"), []byte("\x00\x00"), 2048, 1, 24)
30 | expected := []byte("\x00\xf7\x59\xff\x47\xd1\x4d\xd0\x36\x65\xd5\x94\x3c\xb3\xc4\xa3\x9a\x25\x55\xc0\x2a\xed\x66\xe1")
31 | if bytes.Compare(key, expected) != 0 {
32 | t.Fatalf("expected key '%x', but found '%x'", expected, key)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/debugutils/test/aggregator_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 | "github.com/wx-chevalier/go-utils/debugutils"
7 | "github.com/wx-chevalier/go-utils/tarutils"
8 | "github.com/spf13/afero"
9 | )
10 |
11 | var _ = Describe("aggregator test", func() {
12 | var (
13 | aggregator *debugutils.Aggregator
14 | fs afero.Fs
15 | )
16 |
17 | Context("e2e", func() {
18 | BeforeEach(func() {
19 | fs = afero.NewOsFs()
20 | storageClient := debugutils.NewFileStorageClient(fs)
21 | logCollector, err := debugutils.DefaultLogCollector()
22 | Expect(err).NotTo(HaveOccurred())
23 | resourceCollector, err := debugutils.DefaultResourceCollector()
24 | Expect(err).NotTo(HaveOccurred())
25 | tmpd, err := afero.TempDir(fs, "", "")
26 | Expect(err).NotTo(HaveOccurred())
27 | aggregator = debugutils.NewAggregator(resourceCollector, logCollector, storageClient, fs, tmpd)
28 | })
29 | It("can properly tar up all resources", func() {
30 | tmpf, err := afero.TempFile(fs, "", "")
31 | defer fs.Remove(tmpf.Name())
32 | Expect(err).NotTo(HaveOccurred())
33 | err = aggregator.StreamFromManifest(manifests, "gloo-system", tmpf.Name())
34 | Expect(err).NotTo(HaveOccurred())
35 | tmpd, err := afero.TempDir(fs, "", "")
36 | Expect(err).NotTo(HaveOccurred())
37 | defer fs.RemoveAll(tmpd)
38 | err = tarutils.Untar(tmpd, tmpf.Name(), fs)
39 | Expect(err).NotTo(HaveOccurred())
40 | })
41 | })
42 |
43 | })
44 |
--------------------------------------------------------------------------------
/logutils/defaultlogger.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | // DefaultLogger ...
4 | type DefaultLogger struct {
5 | ts bool
6 | }
7 |
8 | // NewDefaultLogger ...
9 | func NewDefaultLogger(withTimestamp bool) DefaultLogger {
10 | return DefaultLogger{withTimestamp}
11 | }
12 |
13 | // Donef ...
14 | func (dl DefaultLogger) Donef(format string, v ...interface{}) {
15 | fSelect(dl.ts, TDonef, Donef)(format, v...)
16 | }
17 |
18 | // Successf ...
19 | func (dl DefaultLogger) Successf(format string, v ...interface{}) {
20 | fSelect(dl.ts, TSuccessf, Successf)(format, v...)
21 | }
22 |
23 | // Infof ...
24 | func (dl DefaultLogger) Infof(format string, v ...interface{}) {
25 | fSelect(dl.ts, TInfof, Infof)(format, v...)
26 | }
27 |
28 | // Printf ...
29 | func (dl DefaultLogger) Printf(format string, v ...interface{}) {
30 | fSelect(dl.ts, TPrintf, Printf)(format, v...)
31 | }
32 |
33 | // Warnf ...
34 | func (dl DefaultLogger) Warnf(format string, v ...interface{}) {
35 | fSelect(dl.ts, TWarnf, Warnf)(format, v...)
36 | }
37 |
38 | // Errorf ...
39 | func (dl DefaultLogger) Errorf(format string, v ...interface{}) {
40 | fSelect(dl.ts, TErrorf, Errorf)(format, v...)
41 | }
42 |
43 | // Debugf ...
44 | func (dl DefaultLogger) Debugf(format string, v ...interface{}) {
45 | if enableDebugLog {
46 | fSelect(dl.ts, TDebugf, Debugf)(format, v...)
47 | }
48 | }
49 |
50 | type logfunc func(string, ...interface{})
51 |
52 | func fSelect(t bool, tf logfunc, f logfunc) logfunc {
53 | if t {
54 | return tf
55 | }
56 | return f
57 | }
58 |
--------------------------------------------------------------------------------
/strutils/url.go:
--------------------------------------------------------------------------------
1 | package urlutil
2 |
3 | import (
4 | "errors"
5 | "net/url"
6 | "strings"
7 | )
8 |
9 | // Join ...
10 | func Join(elems ...string) (string, error) {
11 | if len(elems) < 1 {
12 | return "", errors.New("No elements defined to Join")
13 | }
14 |
15 | url, err := url.Parse(elems[0])
16 | if err != nil {
17 | return "", err
18 | }
19 | schemeStr := url.Scheme
20 | if schemeStr == "" {
21 | return "", errors.New("No Scheme defined")
22 | }
23 |
24 | hostStr := url.Host
25 | if hostStr == "" {
26 | return "", errors.New("No Host defined")
27 | }
28 |
29 | pathStr := ""
30 | if url.Path != "" {
31 | pathStr = clearPrefix(url.Path)
32 | pathStr = clearSuffix(pathStr)
33 | }
34 |
35 | combined := schemeStr + "://" + hostStr
36 | if pathStr != "" {
37 | combined = combined + "/" + pathStr
38 | }
39 |
40 | for i, e := range elems {
41 | if i > 0 {
42 | if i < len(elems)-1 {
43 | pathStr = clearPrefix(e)
44 | pathStr = clearSuffix(pathStr)
45 |
46 | combined = combined + "/" + pathStr
47 | } else {
48 | pathStr = clearPrefix(e)
49 | combined = combined + "/" + pathStr
50 | }
51 | }
52 | }
53 |
54 | return combined, nil
55 | }
56 |
57 | func clearPrefix(s string) string {
58 | if strings.HasPrefix(s, "/") {
59 | s = s[1:len(s)]
60 | s = clearPrefix(s)
61 | }
62 | return s
63 | }
64 |
65 | func clearSuffix(s string) string {
66 | if strings.HasSuffix(s, "/") {
67 | s = s[0 : len(s)-1]
68 | s = clearSuffix(s)
69 | }
70 | return s
71 | }
72 |
--------------------------------------------------------------------------------
/kubectrlutils/wait_crd_test.go:
--------------------------------------------------------------------------------
1 | package kubeutils_test
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 | . "github.com/wx-chevalier/go-utils/kubeutils"
7 | "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
8 | apiexts "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
9 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | var _ = Describe("WaitCrd", func() {
13 | var (
14 | api apiexts.Interface
15 | crdName = "testing"
16 | )
17 | BeforeEach(func() {
18 | cfg, err := GetConfig("", "")
19 | Expect(err).NotTo(HaveOccurred())
20 | api, err = apiexts.NewForConfig(cfg)
21 | Expect(err).NotTo(HaveOccurred())
22 | crd, err := api.ApiextensionsV1beta1().CustomResourceDefinitions().Create(&v1beta1.CustomResourceDefinition{
23 | ObjectMeta: v1.ObjectMeta{Name: "somethings.test.solo.io"},
24 | Spec: v1beta1.CustomResourceDefinitionSpec{
25 | Group: "test.solo.io",
26 | Names: v1beta1.CustomResourceDefinitionNames{
27 | Plural: "somethings",
28 | Kind: "Something",
29 | ShortNames: []string{"st"},
30 | },
31 | Version: "v1",
32 | },
33 | })
34 | Expect(err).NotTo(HaveOccurred())
35 | crdName = crd.Name
36 | })
37 | AfterEach(func() {
38 | api.ApiextensionsV1beta1().CustomResourceDefinitions().Delete(crdName, nil)
39 | })
40 | It("waits successfully for a crd to become established", func() {
41 | err := WaitForCrdActive(api, crdName)
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 | })
45 |
--------------------------------------------------------------------------------
/strutils/colorstring_test.go:
--------------------------------------------------------------------------------
1 | package colorstring
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestAddColor(t *testing.T) {
11 | /*
12 | blackColor Color = "\x1b[30;1m"
13 | resetColor Color = "\x1b[0m"
14 | */
15 |
16 | t.Log("colored_string = color + string + reset_color")
17 | {
18 | desiredColored := "\x1b[30;1m" + "test" + "\x1b[0m"
19 | colored := addColor(blackColor, "test")
20 | require.Equal(t, desiredColored, colored)
21 | }
22 | }
23 |
24 | func TestBlack(t *testing.T) {
25 | t.Log("Simple string can be blacked")
26 | {
27 | desiredColored := "\x1b[30;1m" + "test" + "\x1b[0m"
28 | colored := Black("test")
29 | require.Equal(t, desiredColored, colored)
30 | }
31 |
32 | t.Log("Multiple strings can be blacked")
33 | {
34 | desiredColored := "\x1b[30;1m" + "Hello Bitrise !" + "\x1b[0m"
35 | colored := Black("Hello ", "Bitrise ", "!")
36 | require.Equal(t, desiredColored, colored)
37 | }
38 | }
39 |
40 | func TestBlackf(t *testing.T) {
41 | t.Log("Simple format can be blacked")
42 | {
43 | desiredColored := "\x1b[30;1m" + fmt.Sprintf("Hello %s", "bitrise") + "\x1b[0m"
44 | colored := Blackf("Hello %s", "bitrise")
45 | require.Equal(t, desiredColored, colored)
46 | }
47 |
48 | t.Log("Complex format can be blacked")
49 | {
50 | desiredColored := "\x1b[30;1m" + fmt.Sprintf("Hello %s %s", "bitrise", "!") + "\x1b[0m"
51 | colored := Blackf("Hello %s %s", "bitrise", "!")
52 | require.Equal(t, desiredColored, colored)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/grpcx/limiters.go:
--------------------------------------------------------------------------------
1 | package grpcx
2 |
3 | import (
4 | "context"
5 | "sync"
6 | "time"
7 |
8 | "golang.org/x/time/rate"
9 | )
10 |
11 | var (
12 | DefaultRateLimiter = NewRateLimiterPool(50, 100)
13 |
14 | // todo: clean
15 | defaultCleanInterval = 6 * time.Hour
16 | )
17 |
18 | type RateLimiterPool struct {
19 | r rate.Limit
20 | b int
21 | limiters map[string]*rate.Limiter
22 | cleanInterval time.Duration
23 |
24 | sync.RWMutex
25 | }
26 |
27 | func NewRateLimiterPool(r rate.Limit, b int) *RateLimiterPool {
28 | l := &RateLimiterPool{
29 | r: r,
30 | b: b,
31 | limiters: make(map[string]*rate.Limiter),
32 | }
33 |
34 | return l
35 | }
36 |
37 | func (l *RateLimiterPool) AddLimiter(tag string) *rate.Limiter {
38 | l.Lock()
39 | defer l.Unlock()
40 |
41 | return l.addLimiter(tag)
42 | }
43 |
44 | func (l *RateLimiterPool) addLimiter(tag string) *rate.Limiter {
45 | limiter := rate.NewLimiter(l.r, l.b)
46 | l.limiters[tag] = limiter
47 |
48 | return limiter
49 | }
50 |
51 | func (l *RateLimiterPool) GetLimiter(tag string) *rate.Limiter {
52 | l.Lock()
53 | defer l.Unlock()
54 |
55 | limiter, exists := l.limiters[tag]
56 | if !exists {
57 | return l.addLimiter(tag)
58 | }
59 |
60 | return limiter
61 | }
62 |
63 | func (l *RateLimiterPool) Allow(tag string) bool {
64 | limiter := l.GetLimiter(tag)
65 | return limiter.Allow()
66 | }
67 |
68 | func (l *RateLimiterPool) Wait(ctx context.Context, tag string) error {
69 | limiter := l.GetLimiter(tag)
70 | return limiter.Wait(ctx)
71 | }
72 |
--------------------------------------------------------------------------------
/errutils/errors.go:
--------------------------------------------------------------------------------
1 | package errutils
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "os/exec"
7 | "regexp"
8 | "strings"
9 | "syscall"
10 |
11 | "golang.org/x/xerrors"
12 | )
13 |
14 | func Wrapf(err error, format string, args ...interface{}) error {
15 | errString := fmt.Sprintf(format, args...)
16 | return xerrors.Errorf("%s: %w", errString, err)
17 | }
18 |
19 | func Errorf(format string, args ...interface{}) error {
20 | return xerrors.Errorf(format, args...)
21 | }
22 |
23 | func Errors(msgs []string) error {
24 | return xerrors.Errorf(strings.Join(msgs, "\n"))
25 | }
26 |
27 | func New(text string) error {
28 | return xerrors.New(text)
29 | }
30 |
31 | func Is(err, target error) bool {
32 | return xerrors.Is(err, target)
33 | }
34 |
35 | // IsExitStatusError ...
36 | func IsExitStatusError(err error) bool {
37 | return IsExitStatusErrorStr(err.Error())
38 | }
39 |
40 | // IsExitStatusErrorStr ...
41 | func IsExitStatusErrorStr(errString string) bool {
42 | // example exit status error string: exit status 1
43 | var rex = regexp.MustCompile(`^exit status [0-9]{1,3}$`)
44 | return rex.MatchString(errString)
45 | }
46 |
47 | // CmdExitCodeFromError ...
48 | func CmdExitCodeFromError(err error) (int, error) {
49 | cmdExitCode := 0
50 | if err != nil {
51 | if exitError, ok := err.(*exec.ExitError); ok {
52 | waitStatus, ok := exitError.Sys().(syscall.WaitStatus)
53 | if !ok {
54 | return 1, errors.New("Failed to cast exit status")
55 | }
56 | cmdExitCode = waitStatus.ExitStatus()
57 | }
58 | return cmdExitCode, nil
59 | }
60 | return 0, nil
61 | }
62 |
--------------------------------------------------------------------------------
/kubectrlutils/util.go:
--------------------------------------------------------------------------------
1 | package kubeutils
2 |
3 | import (
4 | "crypto/md5"
5 | "fmt"
6 | "strings"
7 | )
8 |
9 | // use SanitizeNameV2
10 | // DEPRECATED
11 | func SanitizeName(name string) string {
12 | name = strings.Replace(name, "*", "-", -1)
13 | name = strings.Replace(name, "/", "-", -1)
14 | name = strings.Replace(name, ".", "-", -1)
15 | name = strings.Replace(name, "[", "", -1)
16 | name = strings.Replace(name, "]", "", -1)
17 | name = strings.Replace(name, ":", "-", -1)
18 | name = strings.Replace(name, " ", "-", -1)
19 | name = strings.Replace(name, "\n", "", -1)
20 | if len(name) > 63 {
21 | hash := md5.Sum([]byte(name))
22 | name = fmt.Sprintf("%s-%x", name[:31], hash)
23 | name = name[:63]
24 | }
25 | name = strings.Replace(name, ".", "-", -1)
26 | name = strings.ToLower(name)
27 | return name
28 | }
29 |
30 | func SanitizeNameV2(name string) string {
31 | name = strings.Replace(name, "*", "-", -1)
32 | name = strings.Replace(name, "/", "-", -1)
33 | name = strings.Replace(name, ".", "-", -1)
34 | name = strings.Replace(name, "[", "", -1)
35 | name = strings.Replace(name, "]", "", -1)
36 | name = strings.Replace(name, ":", "-", -1)
37 | name = strings.Replace(name, " ", "-", -1)
38 | name = strings.Replace(name, "\n", "", -1)
39 | name = strings.Replace(name, "\"", "", -1)
40 | name = strings.Replace(name, "'", "", -1)
41 | if len(name) > 63 {
42 | hash := md5.Sum([]byte(name))
43 | name = fmt.Sprintf("%s-%x", name[:31], hash)
44 | name = name[:63]
45 | }
46 | name = strings.Replace(name, ".", "-", -1)
47 | name = strings.ToLower(name)
48 | return name
49 | }
50 |
--------------------------------------------------------------------------------
/dockerutils/pull.go:
--------------------------------------------------------------------------------
1 | package docker
2 |
3 | import (
4 | "context"
5 | "time"
6 |
7 | "github.com/wx-chevalier/go-utils/contextutils"
8 | "github.com/wx-chevalier/go-utils/errutils"
9 | )
10 |
11 | // PullIfNotPresent will pull an image if it is not present locally
12 | // retrying up to retries times
13 | // it returns true if it attempted to pull, and any errors from pulling
14 | func PullIfNotPresent(ctx context.Context, image string, retries int) (pulled bool, err error) {
15 | logger := contextutils.LoggerFrom(ctx)
16 | // if this did not return an error, then the image exists locally
17 | cmd := Command("inspect", "--type=image", image)
18 | if err := cmd.Run(); err == nil {
19 | logger.Infof("Image: %s present locally", image)
20 | return false, nil
21 | }
22 | // otherwise try to pull it
23 | return true, Pull(ctx, image, retries)
24 | }
25 |
26 | // Pull pulls an image, retrying up to retries times
27 | func Pull(ctx context.Context, image string, retries int) error {
28 | logger := contextutils.LoggerFrom(ctx)
29 | logger.Infof("Pulling image: %s ...", image)
30 | err := Command("pull", image).Run()
31 | // retry pulling up to retries times if necessary
32 | if err != nil {
33 | for i := 0; i < retries; i++ {
34 | time.Sleep(time.Second * time.Duration(i+1))
35 | logger.Warnf(errors.Wrapf(err, "Trying again to pull image: %s ...", image).Error())
36 | err = Command("pull", image).Run()
37 | if err == nil {
38 | break
39 | }
40 | }
41 | }
42 | if err != nil {
43 | logger.Warnf(errors.Wrapf(err, "Failed to pull image: %s", image).Error())
44 | }
45 | return err
46 | }
47 |
--------------------------------------------------------------------------------
/stats/README.md:
--------------------------------------------------------------------------------
1 | # Logs
2 |
3 | enable debug logs with
4 |
5 | ```shell
6 | curl -XPUT -d '{"level":"debug"}' -H"content-type: application/json" http://localhost:9091/logging
7 | ```
8 |
9 | # zPages
10 |
11 | see them here:
12 |
13 | localhost:9091/zpages/tracez
14 |
15 | # Local Prometheus
16 |
17 | Start like so:
18 |
19 | ```shell
20 | cat < config.yaml
21 | global:
22 | scrape_interval: 15s # By default, scrape targets every 15 seconds.
23 |
24 | # A scrape configuration containing exactly one endpoint to scrape:
25 | scrape_configs:
26 | # The job name is added as a label 'job=' to any timeseries scraped from this config.
27 | - job_name: 'go-utils'
28 |
29 | # Override the global default and scrape targets from this job every 1 seconds.
30 | scrape_interval: 1s
31 |
32 | static_configs:
33 | - targets: ['localhost:9091']
34 | EOF
35 | prometheus --config.file=./config.yaml
36 | ```
37 |
38 | Prometheus will be available in `localhost:9090`.
39 |
40 | To see the rate of incoming snapshots, try this query:
41 |
42 | ```
43 | rate(api_snap_emitter_snap_in[5m])
44 | ```
45 |
46 | # Profiling
47 |
48 | ## CPU tracing
49 |
50 | ```
51 | $ curl http://localhost:9091/debug/pprof/trace?seconds=5 -o trace.out
52 | $ go tool trace trace.out
53 | ```
54 |
55 | ## profiling
56 |
57 | ```
58 | $ curl http://localhost:9091/debug/pprof/profile?seconds=5 -o pprof.out
59 | $ go tool pprof pprof.out
60 | (pprof) top
61 | (pprof) web
62 | ```
63 |
64 | ## Stack traces
65 |
66 | See go routines:
67 |
68 | ```
69 | $ curl http://localhost:9091/debug/pprof/goroutine?debug=2
70 | ```
71 |
--------------------------------------------------------------------------------
/kubesetuputils/crd.go:
--------------------------------------------------------------------------------
1 | package kubeinstallutils
2 |
3 | import (
4 | "github.com/wx-chevalier/go-utils/errutils"
5 | "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
6 | apiexts "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
7 | apierrors "k8s.io/apimachinery/pkg/api/errors"
8 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | )
10 |
11 | func CrdsFromManifest(crdManifestYaml string) ([]*v1beta1.CustomResourceDefinition, error) {
12 | var crds []*v1beta1.CustomResourceDefinition
13 | crdRuntimeObjects, err := ParseKubeManifest(crdManifestYaml)
14 | if err != nil {
15 | return nil, err
16 | }
17 | for _, obj := range crdRuntimeObjects {
18 | apiExtCrd, ok := obj.(*v1beta1.CustomResourceDefinition)
19 | if !ok {
20 | return nil, errors.Wrapf(err, "internal error: crd manifest must only contain CustomResourceDefinitions")
21 | }
22 | crds = append(crds, apiExtCrd)
23 | }
24 | return crds, nil
25 | }
26 |
27 | func CreateCrds(apiExts apiexts.Interface, crds ...*v1beta1.CustomResourceDefinition) error {
28 | for _, crd := range crds {
29 | if _, err := apiExts.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd); err != nil && !apierrors.IsAlreadyExists(err) {
30 | return errors.Wrapf(err, "failed to create crd: %v", crd)
31 | }
32 | }
33 | return nil
34 | }
35 |
36 | func DeleteCrds(apiExts apiexts.Interface, crdNames ...string) error {
37 | for _, name := range crdNames {
38 | err := apiExts.ApiextensionsV1beta1().CustomResourceDefinitions().Delete(name, &v1.DeleteOptions{})
39 | if err != nil && !apierrors.IsNotFound(err) {
40 | return errors.Wrapf(err, "failed to delete crd: %v", name)
41 | }
42 | }
43 | return nil
44 | }
45 |
--------------------------------------------------------------------------------
/kubeinstallutils/manifests.go:
--------------------------------------------------------------------------------
1 | package installutils
2 |
3 | import (
4 | "path/filepath"
5 | "regexp"
6 | "strings"
7 |
8 | "helm.sh/helm/v3/pkg/releaseutil"
9 |
10 | "github.com/wx-chevalier/go-utils/vfsutils"
11 | "github.com/spf13/afero"
12 | )
13 |
14 | var (
15 | kindRegex = regexp.MustCompile("kind:(.*)\n")
16 | )
17 |
18 | func GetManifestsFromRemoteTar(tarUrl string) ([]releaseutil.Manifest, error) {
19 | fs := afero.NewMemMapFs()
20 | dir, err := vfsutils.MountTar(fs, tarUrl)
21 | if err != nil {
22 | return nil, err
23 | }
24 | files, err := afero.ReadDir(fs, dir)
25 | if err != nil {
26 | return nil, err
27 | }
28 | templates := make(map[string]string)
29 | for _, file := range files {
30 | filename := filepath.Join(dir, file.Name())
31 | contents, err := afero.ReadFile(fs, filename)
32 | if err != nil {
33 | return nil, err
34 | }
35 | templates[filename] = string(contents)
36 | }
37 | return SplitManifests(templates), nil
38 | }
39 |
40 | // SplitManifests takes a map of rendered templates and splits them into the
41 | // detected manifests.
42 | // (ported from Helm 2: https://github.com/helm/helm/blob/release-2.16/pkg/manifest/splitter.go)
43 | func SplitManifests(templates map[string]string) []releaseutil.Manifest {
44 | var listManifests []releaseutil.Manifest
45 | // extract kind and name
46 | for k, v := range templates {
47 | match := kindRegex.FindStringSubmatch(v)
48 | h := "Unknown"
49 | if len(match) == 2 {
50 | h = strings.TrimSpace(match[1])
51 | }
52 | m := releaseutil.Manifest{Name: k, Content: v, Head: &releaseutil.SimpleHead{Kind: h}}
53 | listManifests = append(listManifests, m)
54 | }
55 |
56 | return listManifests
57 | }
58 |
--------------------------------------------------------------------------------
/dockerutils/docker_test.go:
--------------------------------------------------------------------------------
1 | package docker_test
2 |
3 | import (
4 | "context"
5 | "io/ioutil"
6 | "os/exec"
7 |
8 | . "github.com/onsi/ginkgo"
9 | . "github.com/onsi/gomega"
10 | "github.com/wx-chevalier/go-utils/docker"
11 | )
12 |
13 | const (
14 | validImage = "soloio/gloo:0.7.0"
15 | invalidImage = "soloio/gloo:0.1.0"
16 | )
17 |
18 | var _ = BeforeSuite(func() {
19 | exec.Command("docker", "image", "rm", validImage).Run()
20 | })
21 |
22 | var _ = Describe("Docker", func() {
23 |
24 | pullValidImage := func() bool {
25 | ok, err := docker.PullIfNotPresent(context.TODO(), validImage, 1)
26 | Expect(err).NotTo(HaveOccurred())
27 | return ok
28 | }
29 |
30 | pullInvalidImage := func() {
31 | _, err := docker.PullIfNotPresent(context.TODO(), invalidImage, 1)
32 | Expect(err).To(HaveOccurred())
33 | }
34 |
35 | Context("Pull", func() {
36 | It("can pull a valid container", func() {
37 | Expect(pullValidImage()).To(Equal(true))
38 | Expect(pullValidImage()).To(Equal(false))
39 | })
40 |
41 | It("cannot pull an invalid container", func() {
42 | pullInvalidImage()
43 | })
44 |
45 | })
46 |
47 | Context("Save", func() {
48 | It("can save a valid, present container", func() {
49 | pullValidImage()
50 | file, err := ioutil.TempFile("", "docker_test")
51 | Expect(err).NotTo(HaveOccurred())
52 | err = docker.Save(validImage, file.Name())
53 | Expect(err).NotTo(HaveOccurred())
54 | })
55 |
56 | It("cannot save an invalid container", func() {
57 | file, err := ioutil.TempFile("", "docker_test")
58 | Expect(err).NotTo(HaveOccurred())
59 | err = docker.Save(invalidImage, file.Name())
60 | Expect(err).To(HaveOccurred())
61 | })
62 | })
63 |
64 | })
65 |
--------------------------------------------------------------------------------
/pkcs12utils/bmp-string.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package pkcs12
6 |
7 | import (
8 | "errors"
9 | "unicode/utf16"
10 | )
11 |
12 | // bmpString returns s encoded in UCS-2 with a zero terminator.
13 | func bmpString(s string) ([]byte, error) {
14 | // References:
15 | // https://tools.ietf.org/html/rfc7292#appendix-B.1
16 | // https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
17 | // - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes
18 | // EncodeRune returns 0xfffd if the rune does not need special encoding
19 | // - the above RFC provides the info that BMPStrings are NULL terminated.
20 |
21 | ret := make([]byte, 0, 2*len(s)+2)
22 |
23 | for _, r := range s {
24 | if t, _ := utf16.EncodeRune(r); t != 0xfffd {
25 | return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2")
26 | }
27 | ret = append(ret, byte(r/256), byte(r%256))
28 | }
29 |
30 | return append(ret, 0, 0), nil
31 | }
32 |
33 | func decodeBMPString(bmpString []byte) (string, error) {
34 | if len(bmpString)%2 != 0 {
35 | return "", errors.New("pkcs12: odd-length BMP string")
36 | }
37 |
38 | // strip terminator if present
39 | if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
40 | bmpString = bmpString[:l-2]
41 | }
42 |
43 | s := make([]uint16, 0, len(bmpString)/2)
44 | for len(bmpString) > 0 {
45 | s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
46 | bmpString = bmpString[2:]
47 | }
48 |
49 | return string(utf16.Decode(s)), nil
50 | }
51 |
--------------------------------------------------------------------------------
/logutils/print_test.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "bytes"
5 | "regexp"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_printf_with_time(t *testing.T) {
12 | SetTimestampLayout("15.04.05")
13 | var b bytes.Buffer
14 | SetOutWriter(&b)
15 | printf(normalSeverity, true, "test %s", "log")
16 | re := regexp.MustCompile(`\[.+\..+\..+\] test log`)
17 | require.True(t, re.MatchString(b.String()), b.String())
18 | }
19 |
20 | func Test_printf_severity(t *testing.T) {
21 | t.Log("error")
22 | {
23 | var b bytes.Buffer
24 | SetOutWriter(&b)
25 | printf(errorSeverity, false, "test %s", "log")
26 | require.Equal(t, "\x1b[31;1mtest log\x1b[0m\n", b.String())
27 | }
28 |
29 | t.Log("warn")
30 | {
31 | var b bytes.Buffer
32 | SetOutWriter(&b)
33 | printf(warnSeverity, false, "test %s", "log")
34 | require.Equal(t, "\x1b[33;1mtest log\x1b[0m\n", b.String())
35 | }
36 |
37 | t.Log("debug")
38 | {
39 | var b bytes.Buffer
40 | SetOutWriter(&b)
41 | printf(debugSeverity, false, "test %s", "log")
42 | require.Equal(t, "\x1b[35;1mtest log\x1b[0m\n", b.String())
43 | }
44 |
45 | t.Log("normal")
46 | {
47 | var b bytes.Buffer
48 | SetOutWriter(&b)
49 | printf(normalSeverity, false, "test %s", "log")
50 | require.Equal(t, "test log\n", b.String())
51 | }
52 |
53 | t.Log("info")
54 | {
55 | var b bytes.Buffer
56 | SetOutWriter(&b)
57 | printf(infoSeverity, false, "test %s", "log")
58 | require.Equal(t, "\x1b[34;1mtest log\x1b[0m\n", b.String())
59 | }
60 |
61 | t.Log("success")
62 | {
63 | var b bytes.Buffer
64 | SetOutWriter(&b)
65 | printf(successSeverity, false, "test %s", "log")
66 | require.Equal(t, "\x1b[32;1mtest log\x1b[0m\n", b.String())
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/pkcs12utils/mac.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015, 2018, 2019 Opsmate, Inc. All rights reserved.
2 | // Copyright 2015 The Go Authors. All rights reserved.
3 | // Use of this source code is governed by a BSD-style
4 | // license that can be found in the LICENSE file.
5 |
6 | package pkcs12
7 |
8 | import (
9 | "crypto/hmac"
10 | "crypto/sha1"
11 | "crypto/x509/pkix"
12 | "encoding/asn1"
13 | )
14 |
15 | type macData struct {
16 | Mac digestInfo
17 | MacSalt []byte
18 | Iterations int `asn1:"optional,default:1"`
19 | }
20 |
21 | // from PKCS#7:
22 | type digestInfo struct {
23 | Algorithm pkix.AlgorithmIdentifier
24 | Digest []byte
25 | }
26 |
27 | var (
28 | oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
29 | )
30 |
31 | func verifyMac(macData *macData, message, password []byte) error {
32 | if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
33 | return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
34 | }
35 |
36 | key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20)
37 |
38 | mac := hmac.New(sha1.New, key)
39 | mac.Write(message)
40 | expectedMAC := mac.Sum(nil)
41 |
42 | if !hmac.Equal(macData.Mac.Digest, expectedMAC) {
43 | return ErrIncorrectPassword
44 | }
45 | return nil
46 | }
47 |
48 | func computeMac(macData *macData, message, password []byte) error {
49 | if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
50 | return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
51 | }
52 |
53 | key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20)
54 |
55 | mac := hmac.New(sha1.New, key)
56 | mac.Write(message)
57 | macData.Mac.Digest = mac.Sum(nil)
58 |
59 | return nil
60 | }
61 |
--------------------------------------------------------------------------------
/errutils/errors_test.go:
--------------------------------------------------------------------------------
1 | package errutils
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestIsExitStatusErrorStr(t *testing.T) {
10 | // --- Should match ---
11 | require.Equal(t, true, IsExitStatusErrorStr("exit status 1"))
12 | require.Equal(t, true, IsExitStatusErrorStr("exit status 0"))
13 | require.Equal(t, true, IsExitStatusErrorStr("exit status 2"))
14 | require.Equal(t, true, IsExitStatusErrorStr("exit status 11"))
15 | require.Equal(t, true, IsExitStatusErrorStr("exit status 111"))
16 | require.Equal(t, true, IsExitStatusErrorStr("exit status 999"))
17 |
18 | // --- Should not match ---
19 | require.Equal(t, false, IsExitStatusErrorStr("xit status 1"))
20 | require.Equal(t, false, IsExitStatusErrorStr("status 1"))
21 | require.Equal(t, false, IsExitStatusErrorStr("exit status "))
22 | require.Equal(t, false, IsExitStatusErrorStr("exit status"))
23 | require.Equal(t, false, IsExitStatusErrorStr("exit status 2112"))
24 | require.Equal(t, false, IsExitStatusErrorStr("exit status 21121"))
25 |
26 | // prefixed
27 | require.Equal(t, false, IsExitStatusErrorStr(".exit status 1"))
28 | require.Equal(t, false, IsExitStatusErrorStr(" exit status 1"))
29 | require.Equal(t, false, IsExitStatusErrorStr("error: exit status 1"))
30 | // postfixed
31 | require.Equal(t, false, IsExitStatusErrorStr("exit status 1."))
32 | require.Equal(t, false, IsExitStatusErrorStr("exit status 1 "))
33 | require.Equal(t, false, IsExitStatusErrorStr("exit status 1 - something else"))
34 | require.Equal(t, false, IsExitStatusErrorStr("exit status 1 2"))
35 |
36 | // other
37 | require.Equal(t, false, IsExitStatusErrorStr("-exit status 211-"))
38 | require.Equal(t, false, IsExitStatusErrorStr("something else: exit status 1"))
39 | }
40 |
--------------------------------------------------------------------------------
/testutils/fail_handler.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "os"
7 | "os/signal"
8 | "runtime/debug"
9 | "strings"
10 | "syscall"
11 |
12 | . "github.com/onsi/ginkgo"
13 | . "github.com/onsi/gomega"
14 | )
15 |
16 | func waitOnFail() {
17 |
18 | if os.Getenv("WAIT_ON_FAIL") == "0" {
19 | return
20 | }
21 |
22 | if os.Getenv("WAIT_ON_FAIL") == "1" || IsDebuggerPresent() {
23 | // wait for sig usr1
24 | c := make(chan os.Signal, 1)
25 | signal.Notify(c, syscall.SIGUSR1)
26 | defer signal.Reset(syscall.SIGUSR1)
27 | fmt.Println("We are here:")
28 | debug.PrintStack()
29 | fmt.Printf("Waiting for human intervention. to continue, run 'kill -SIGUSR1 %d'\n", os.Getpid())
30 | <-c
31 | }
32 | }
33 |
34 | var preFails []func()
35 |
36 | func RegisterPreFailHandler(prefail func()) {
37 | preFails = append(preFails, prefail)
38 | }
39 |
40 | func RegisterCommonFailHandlers() {
41 | RegisterPreFailHandler(waitOnFail)
42 | RegisterFailHandler(failHandler)
43 | }
44 |
45 | func failHandler(message string, callerSkip ...int) {
46 | fmt.Println("Fail handler msg", message)
47 |
48 | for _, prefail := range preFails {
49 | prefail()
50 | }
51 | Fail(message, callerSkip...)
52 |
53 | }
54 |
55 | func IsDebuggerPresent() bool {
56 | f, err := ioutil.ReadFile("/proc/self/status")
57 | if err != nil {
58 | // no status so we don't know
59 | return false
60 | }
61 | status := string(f)
62 | if !strings.Contains(status, "TracerPid:") {
63 | // no tracer pid field, so we don't know
64 | return false
65 | }
66 |
67 | if strings.Contains(status, "TracerPid:\t0") {
68 | // no tracer pid - no debugger
69 | return false
70 | }
71 | // tracer pid is present and not zero - we have a debugger
72 | return true
73 | }
74 |
--------------------------------------------------------------------------------
/fileutils/file_crud.go:
--------------------------------------------------------------------------------
1 | package fileutils
2 |
3 | import (
4 | "errors"
5 | "os"
6 | "strings"
7 |
8 | command "github.com/wx-chevalier/go-utils/commandutils"
9 | )
10 |
11 | // CopyFile ...
12 | func CopyFile(src, dst string) error {
13 | // replace with a pure Go implementation?
14 | // Golang proposal was: https://go-review.googlesource.com/#/c/1591/5/src/io/ioutil/ioutil.go
15 | isDir, err := IsDirExists(src)
16 | if err != nil {
17 | return err
18 | }
19 | if isDir {
20 | return errors.New("Source is a directory: " + src)
21 | }
22 | args := []string{src, dst}
23 | return command.RunCommand("rsync", args...)
24 | }
25 |
26 | // CopyDir ...
27 | func CopyDir(src, dst string, isOnlyContent bool) error {
28 | if isOnlyContent && !strings.HasSuffix(src, "/") {
29 | src = src + "/"
30 | }
31 | args := []string{"-ar", src, dst}
32 | return command.RunCommand("rsync", args...)
33 | }
34 |
35 | // RemoveDir ...
36 | // Deprecated: use RemoveAll instead.
37 | func RemoveDir(dirPth string) error {
38 | if exist, err := IsPathExists(dirPth); err != nil {
39 | return err
40 | } else if exist {
41 | if err := os.RemoveAll(dirPth); err != nil {
42 | return err
43 | }
44 | }
45 | return nil
46 | }
47 |
48 | // RemoveFile ...
49 | // Deprecated: use RemoveAll instead.
50 | func RemoveFile(pth string) error {
51 | if exist, err := IsPathExists(pth); err != nil {
52 | return err
53 | } else if exist {
54 | if err := os.Remove(pth); err != nil {
55 | return err
56 | }
57 | }
58 | return nil
59 | }
60 |
61 | // RemoveAll removes recursively every file on the given paths.
62 | func RemoveAll(pths ...string) error {
63 | for _, pth := range pths {
64 | if err := os.RemoveAll(pth); err != nil {
65 | return err
66 | }
67 | }
68 | return nil
69 | }
70 |
--------------------------------------------------------------------------------
/debugutils/debugutils_suite_test.go:
--------------------------------------------------------------------------------
1 | package debugutils
2 |
3 | import (
4 | "context"
5 | "os"
6 | "testing"
7 |
8 | "cloud.google.com/go/storage"
9 | "github.com/golang/mock/gomock"
10 | . "github.com/onsi/ginkgo"
11 | . "github.com/onsi/gomega"
12 | "github.com/wx-chevalier/go-utils/installutils/helmchart"
13 | "github.com/wx-chevalier/go-utils/installutils/kuberesource"
14 | "google.golang.org/api/iterator"
15 | )
16 |
17 | func TestDebugutils(t *testing.T) {
18 | T = t
19 | RegisterFailHandler(Fail)
20 | RunSpecs(t, "Debugutils Suite")
21 | }
22 |
23 | var (
24 | T *testing.T
25 | ns string
26 | ctrl *gomock.Controller
27 |
28 | manifests helmchart.Manifests
29 | unstructuredResources kuberesource.UnstructuredResources
30 |
31 | _ = SynchronizedBeforeSuite(func() []byte {
32 | var err error
33 | manifests, err = helmchart.RenderManifests(
34 | context.TODO(),
35 | "https://storage.googleapis.com/solo-public-helm/charts/gloo-0.13.33.tgz",
36 | "",
37 | "aaa",
38 | "gloo-system",
39 | "",
40 | )
41 | Expect(err).NotTo(HaveOccurred())
42 | unstructuredResources, err = manifests.ResourceList()
43 | Expect(err).NotTo(HaveOccurred())
44 | return nil
45 | }, func(data []byte) {})
46 |
47 | _ = SynchronizedAfterSuite(func() {}, func() {
48 | ctx := context.TODO()
49 | client, err := storage.NewClient(ctx)
50 | Expect(err).NotTo(HaveOccurred())
51 | bucket := client.Bucket("go-utils-test")
52 | obj := os.ExpandEnv("$BUILD_ID")
53 | it := bucket.Objects(ctx, &storage.Query{
54 | Prefix: obj,
55 | })
56 | for {
57 | objAttrs, err := it.Next()
58 | if err != nil && err == iterator.Done {
59 | break
60 | }
61 | Expect(err).NotTo(HaveOccurred())
62 | Expect(bucket.Object(objAttrs.Name).Delete(ctx)).NotTo(HaveOccurred())
63 | }
64 | })
65 | )
66 |
--------------------------------------------------------------------------------
/githubutils/README.md:
--------------------------------------------------------------------------------
1 | ## Uploading Release Assets to Github
2 |
3 | To upload release assets to Github, follow these steps (requires go-utils 0.2.10+).
4 |
5 | ### Create a Go script
6 |
7 | Create a script `upload_github_release_asset.go`, like this:
8 |
9 | ```go
10 | package main
11 |
12 | import (
13 | "github.com/wx-chevalier/go-utils/githubutils"
14 | )
15 |
16 | func main() {
17 | assets := make([]githubutils.ReleaseAssetSpec, 2)
18 | assets[0] = githubutils.ReleaseAssetSpec{
19 | Name: "hello",
20 | ParentPath: "_output",
21 | UploadSHA: true,
22 | }
23 | assets[1] = githubutils.ReleaseAssetSpec{
24 | Name: "my-resource.yaml",
25 | ParentPath: "namespace",
26 | }
27 | spec := githubutils.UploadReleaseAssetSpec{
28 | Owner: "wx-chevalier",
29 | Repo: "testrepo",
30 | Assets: assets,
31 | SkipAlreadyExists: true,
32 | }
33 | githubutils.UploadReleaseAssetCli(&spec)
34 | }
35 | ```
36 |
37 | ### Create a Make target
38 |
39 | ```bash
40 | #----------------------------------------------------------------------------------
41 | # Github Assets
42 | #----------------------------------------------------------------------------------
43 |
44 | .PHONY: upload-github-release-assets
45 | upload-github-release-assets: hello
46 | go run upload_github_release_assets.go
47 | ```
48 |
49 | ### Update cloudbuild.yaml to call this target
50 |
51 | ```yaml
52 | steps:
53 | - name: 'gcr.io/solo-corp/go-mod-make:0.1.1'
54 | args: [..., 'upload-github-release-assets', ...]
55 | secretEnv: ['GITHUB_TOKEN']
56 | env:
57 | - 'TAGGED_VERSION=$TAG_NAME'
58 | ```
59 |
60 | Make sure `GITHUB_TOKEN` and `TAGGED_VERSION` are in the environment.
61 |
62 | ### Notes
63 |
64 | * On each asset, a flag `UploadSHA` can be set to true to upload a SHA256 hash file.
65 | * Set `SkipAlreadyExists=true` to not fail when trying to upload an asset that already exists.
--------------------------------------------------------------------------------
/fileutils/messages_test.go:
--------------------------------------------------------------------------------
1 | package fileutils
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | "testing"
7 |
8 | "github.com/gogo/protobuf/types"
9 | "github.com/stretchr/testify/require"
10 | "github.com/stretchr/testify/suite"
11 | )
12 |
13 | // Basic imports
14 |
15 | // Define the suite, and absorb the built-in basic suite
16 | // functionality from testify - including a T() method which
17 | // returns the current testing context
18 | type ExampleTestSuite struct {
19 | suite.Suite
20 | VariableThatShouldStartAtFive int
21 | }
22 |
23 | // Make sure that VariableThatShouldStartAtFive is set to five
24 | // before each test
25 | func (suite *ExampleTestSuite) SetupTest() {
26 | suite.VariableThatShouldStartAtFive = 5
27 | }
28 |
29 | // All methods that begin with "Test" are run as tests within a
30 | // suite.
31 | func (suite *ExampleTestSuite) TestExample() {
32 | var filename string
33 |
34 | f, err := ioutil.TempFile("", "messages_test")
35 | require.Nil(suite.T(), err)
36 | filename = f.Name()
37 | require.Contains(suite.T(), filename, "messages_test")
38 |
39 | input := &types.Struct{
40 | Fields: map[string]*types.Value{
41 | "foo": {
42 | Kind: &types.Value_StringValue{StringValue: "bar"},
43 | },
44 | },
45 | }
46 |
47 | err = WriteToFile(filename, input)
48 | require.Nil(suite.T(), err)
49 |
50 | b, err := ioutil.ReadFile(filename)
51 | require.Nil(suite.T(), err)
52 |
53 | require.Equal(suite.T(), string(b), "foo: bar\n")
54 |
55 | var output types.Struct
56 | err = ReadFileInto(filename, &output)
57 | require.Nil(suite.T(), err)
58 | require.Equal(suite.T(), output, *input)
59 |
60 | os.RemoveAll(filename)
61 | }
62 |
63 | // In order for 'go test' to run this suite, we need to create
64 | // a normal test function and pass our suite to suite.Run
65 | func TestExampleTestSuite(t *testing.T) {
66 | suite.Run(t, new(ExampleTestSuite))
67 | }
68 |
--------------------------------------------------------------------------------
/kubectrlutils/kube_cfg.go:
--------------------------------------------------------------------------------
1 | package kubeutils
2 |
3 | import (
4 | "os"
5 |
6 | _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
7 | "k8s.io/client-go/rest"
8 | "k8s.io/client-go/tools/clientcmd"
9 | clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
10 | )
11 |
12 | // GetConfig gets the kubernetes client config
13 | func GetConfig(masterURL, kubeconfigPath string) (*rest.Config, error) {
14 | envVarName := clientcmd.RecommendedConfigPathEnvVar
15 | if kubeconfigPath == "" && masterURL == "" && os.Getenv(envVarName) == "" {
16 | // Neither kubeconfig nor master URL nor envVarName(KUBECONFIG) was specified. Using the inClusterConfig.
17 | kubeconfig, err := rest.InClusterConfig()
18 | if err == nil {
19 | return kubeconfig, nil
20 | }
21 | // error creating inClusterConfig, falling back to default config
22 | }
23 |
24 | if kubeconfigPath != "" {
25 | if _, err := os.Stat(kubeconfigPath); os.IsNotExist(err) {
26 | // the specified kubeconfig does not exist so fallback to default
27 | kubeconfigPath = ""
28 | }
29 | }
30 |
31 | loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
32 | loadingRules.ExplicitPath = kubeconfigPath
33 | configOverrides := &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterURL}}
34 |
35 | return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides).ClientConfig()
36 | }
37 |
38 | // GetConfig gets the kubernetes client config
39 | func GetKubeConfig(masterURL, kubeconfigPath string) (*clientcmdapi.Config, error) {
40 | loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
41 | loadingRules.ExplicitPath = kubeconfigPath
42 | configOverrides := &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterURL}}
43 |
44 | return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides).ConfigAccess().GetStartingConfig()
45 | }
46 |
--------------------------------------------------------------------------------
/pkcs12utils/bmp-string_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package pkcs12
6 |
7 | import (
8 | "bytes"
9 | "encoding/hex"
10 | "testing"
11 | )
12 |
13 | var bmpStringTests = []struct {
14 | in string
15 | expectedHex string
16 | shouldFail bool
17 | }{
18 | {"", "0000", false},
19 | // Example from https://tools.ietf.org/html/rfc7292#appendix-B.
20 | {"Beavis", "0042006500610076006900730000", false},
21 | // Some characters from the "Letterlike Symbols Unicode block".
22 | {"\u2115 - Double-struck N", "21150020002d00200044006f00750062006c0065002d00730074007200750063006b0020004e0000", false},
23 | // any character outside the BMP should trigger an error.
24 | {"\U0001f000 East wind (Mahjong)", "", true},
25 | }
26 |
27 | func TestBMPString(t *testing.T) {
28 | for i, test := range bmpStringTests {
29 | expected, err := hex.DecodeString(test.expectedHex)
30 | if err != nil {
31 | t.Fatalf("#%d: failed to decode expectation", i)
32 | }
33 |
34 | out, err := bmpString(test.in)
35 | if err == nil && test.shouldFail {
36 | t.Errorf("#%d: expected to fail, but produced %x", i, out)
37 | continue
38 | }
39 |
40 | if err != nil && !test.shouldFail {
41 | t.Errorf("#%d: failed unexpectedly: %s", i, err)
42 | continue
43 | }
44 |
45 | if !test.shouldFail {
46 | if !bytes.Equal(out, expected) {
47 | t.Errorf("#%d: expected %s, got %x", i, test.expectedHex, out)
48 | continue
49 | }
50 |
51 | roundTrip, err := decodeBMPString(out)
52 | if err != nil {
53 | t.Errorf("#%d: decoding output gave an error: %s", i, err)
54 | continue
55 | }
56 |
57 | if roundTrip != test.in {
58 | t.Errorf("#%d: decoding output resulted in %q, but it should have been %q", i, roundTrip, test.in)
59 | continue
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/debugutils/test/pods_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/ghodss/yaml"
5 | . "github.com/onsi/ginkgo"
6 | . "github.com/onsi/gomega"
7 | "github.com/wx-chevalier/go-utils/debugutils"
8 | "github.com/wx-chevalier/go-utils/installutils/kuberesource"
9 | corev1 "k8s.io/api/core/v1"
10 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
11 | "k8s.io/apimachinery/pkg/runtime"
12 | "k8s.io/client-go/kubernetes/fake"
13 | )
14 |
15 | var _ = Describe("pod unit tests", func() {
16 | Context("Label Pod Finder", func() {
17 | var (
18 | podFinder *debugutils.LabelPodFinder
19 | clientset *fake.Clientset
20 | )
21 |
22 | BeforeEach(func() {
23 | clientset = fake.NewSimpleClientset(podsAsObjects(GeneratePodList())...)
24 | podFinder = debugutils.NewLabelPodFinder(clientset)
25 | })
26 |
27 | It("can handle full use case", func() {
28 | resources, err := manifests.ResourceList()
29 | Expect(err).NotTo(HaveOccurred())
30 | list, err := podFinder.GetPods(resources)
31 | Expect(err).NotTo(HaveOccurred())
32 | Expect(list).To(HaveLen(4))
33 | for _, v := range list {
34 | Expect(v.Items).NotTo(HaveLen(0))
35 | }
36 | })
37 |
38 | It("can work with an individual pod", func() {
39 | var unstructuredPod unstructured.Unstructured
40 | err := yaml.Unmarshal([]byte(GlooPodYaml), &unstructuredPod)
41 | Expect(err).NotTo(HaveOccurred())
42 | list, err := podFinder.GetPods(kuberesource.UnstructuredResources{&unstructuredPod})
43 | Expect(err).NotTo(HaveOccurred())
44 | Expect(list).To(HaveLen(1))
45 | Expect(list[0].Items).To(HaveLen(1))
46 | pod := list[0].Items[0]
47 | Expect(pod.GetName()).To(ContainSubstring("gloo"))
48 | })
49 | })
50 | })
51 |
52 | func podsAsObjects(list *corev1.PodList) []runtime.Object {
53 | result := make([]runtime.Object, len(list.Items))
54 | for i, v := range list.Items {
55 | v := v
56 | result[i] = &v
57 | }
58 | return result
59 | }
60 |
--------------------------------------------------------------------------------
/shell/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
6 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
9 | github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
10 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
11 | github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
12 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
13 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
14 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
15 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
16 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
17 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
18 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
19 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
20 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
21 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
22 |
--------------------------------------------------------------------------------
/debugutils/test/resources_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "strings"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | "github.com/wx-chevalier/go-utils/debugutils"
9 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | var _ = Describe("resource collector e2e", func() {
13 | var (
14 | collector debugutils.ResourceCollector
15 | )
16 |
17 | var (
18 | containsPrefixToString = func(s string, prefixes []string) bool {
19 | for _, prefix := range prefixes {
20 | if strings.HasPrefix(s, prefix) {
21 | return true
22 | }
23 | }
24 | return false
25 | }
26 | )
27 |
28 | Context("e2e", func() {
29 | BeforeEach(func() {
30 | var err error
31 | collector, err = debugutils.DefaultResourceCollector()
32 | Expect(err).NotTo(HaveOccurred())
33 | })
34 | It("can retrieve all gloo resources", func() {
35 | unstructured, err := manifests.ResourceList()
36 | Expect(err).NotTo(HaveOccurred())
37 | collectedResources, err := collector.RetrieveResources(unstructured, "", v1.ListOptions{})
38 | Expect(err).NotTo(HaveOccurred())
39 | for _, resource := range collectedResources {
40 | switch resource.GVK.Kind {
41 | case "ConfigMap":
42 | Expect(resource.Resources).To(HaveLen(1))
43 | Expect(resource.Resources[0].GetName()).To(Equal("gateway-proxy-envoy-config"))
44 | case "Pod":
45 | Expect(resource.Resources).To(HaveLen(4))
46 | var deploymentNames []string
47 | for _, v := range unstructuredResources {
48 | if v.GetKind() == "Deployment" {
49 | deploymentNames = append(deploymentNames, v.GetName())
50 | }
51 | }
52 | var podNames []string
53 | for _, v := range resource.Resources {
54 | podNames = append(podNames, v.GetName())
55 | }
56 | for _, v := range podNames {
57 | Expect(containsPrefixToString(v, deploymentNames)).To(BeTrue())
58 | }
59 | }
60 |
61 | }
62 | })
63 | })
64 | })
65 |
--------------------------------------------------------------------------------
/sliceutils/sliceutil_test.go:
--------------------------------------------------------------------------------
1 | package sliceutil
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/wx-chevalier/go-utils/testutil"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestUniqueStringSlice(t *testing.T) {
11 | require.Equal(t, []string{}, UniqueStringSlice([]string{}))
12 | require.Equal(t, []string{"one"}, UniqueStringSlice([]string{"one"}))
13 | testutil.EqualSlicesWithoutOrder(t,
14 | []string{"one", "two"},
15 | UniqueStringSlice([]string{"one", "two"}))
16 | testutil.EqualSlicesWithoutOrder(t,
17 | []string{"one", "two", "three"},
18 | UniqueStringSlice([]string{"one", "two", "three", "two", "one"}))
19 | }
20 |
21 | func TestIndexOfStringInSlice(t *testing.T) {
22 | t.Log("Empty slice")
23 | require.Equal(t, -1, IndexOfStringInSlice("abc", []string{}))
24 |
25 | testSlice := []string{"abc", "def", "123", "456", "123"}
26 |
27 | t.Log("Find item")
28 | require.Equal(t, 0, IndexOfStringInSlice("abc", testSlice))
29 | require.Equal(t, 1, IndexOfStringInSlice("def", testSlice))
30 | require.Equal(t, 3, IndexOfStringInSlice("456", testSlice))
31 |
32 | t.Log("Find first item, if multiple")
33 | require.Equal(t, 2, IndexOfStringInSlice("123", testSlice))
34 |
35 | t.Log("Item is not in the slice")
36 | require.Equal(t, -1, IndexOfStringInSlice("cba", testSlice))
37 | }
38 |
39 | func TestIsStringInSlice(t *testing.T) {
40 | t.Log("Empty slice")
41 | require.Equal(t, false, IsStringInSlice("abc", []string{}))
42 |
43 | testSlice := []string{"abc", "def", "123", "456", "123"}
44 |
45 | t.Log("Find item")
46 | require.Equal(t, true, IsStringInSlice("abc", testSlice))
47 | require.Equal(t, true, IsStringInSlice("def", testSlice))
48 | require.Equal(t, true, IsStringInSlice("456", testSlice))
49 |
50 | t.Log("Find first item, if multiple")
51 | require.Equal(t, true, IsStringInSlice("123", testSlice))
52 |
53 | t.Log("Item is not in the slice")
54 | require.Equal(t, false, IsStringInSlice("cba", testSlice))
55 | }
56 |
--------------------------------------------------------------------------------
/shell/yum.go:
--------------------------------------------------------------------------------
1 | package shell
2 |
3 | type Yum struct {
4 | cmd *Cmd
5 | pkg string
6 | timeout int
7 | }
8 |
9 | type yumOption func(*Yum) error
10 |
11 | func WithYumTimeout(timeout int) yumOption {
12 | return func(y *Yum) error {
13 | y.timeout = timeout
14 | return nil
15 | }
16 | }
17 |
18 | func NewYumCommand(pkg string, options ...yumOption) *Yum {
19 | yum := &Yum{
20 | pkg: pkg,
21 | timeout: -1,
22 | }
23 |
24 | for _, opt := range options {
25 | opt(yum)
26 | }
27 |
28 | if yum.timeout > 0 {
29 | yum.cmd = NewCommand("yum install -y "+yum.pkg, WithShellMode(), WithTimeout(yum.timeout))
30 | } else {
31 | yum.cmd = NewCommand("yum install -y "+yum.pkg, WithShellMode())
32 | }
33 |
34 | return yum
35 | }
36 |
37 | func (y *Yum) YumInstallStart() {
38 | y.cmd.Start()
39 | }
40 |
41 | func (y *Yum) YumWait() (string, error) {
42 | y.cmd.Wait()
43 | status := y.cmd.Status
44 |
45 | if status.Error == nil && status.ExitCode == 0 {
46 | return status.Output, nil
47 | }
48 | return status.Output, status.Error
49 | }
50 |
51 | // YumInstall yum install synchorize.
52 | func YumInstall(pkg string) (string, error) {
53 | out, code, err := Command("yum -y install " + pkg)
54 | if code == 1 && err != nil {
55 | return out, err
56 | }
57 | return out, nil
58 | }
59 |
60 | // yum remove pkg.
61 | func YumRemove(pkg string) error {
62 | _, code, err := Command("yum -y remove " + pkg)
63 | if code == 0 && err == nil {
64 | return nil
65 | }
66 | return err
67 | }
68 |
69 | // YumInstallAsync Install asynchorize.
70 | // Usage: YumInstallAsync("docker", WithTimeout(1)).Then(func(res string, err error){fmt.Println(res, err)})
71 | func YumInstallAsync(pkg string, options ...yumOption) *Yum {
72 | yumCmd := NewYumCommand(pkg, options...)
73 | yumCmd.YumInstallStart()
74 | return yumCmd
75 | }
76 |
77 | func (y *Yum) Then(f func(string, error)) {
78 | go func(y *Yum) {
79 | res, err := y.YumWait()
80 | f(res, err)
81 | }(y)
82 | }
83 |
--------------------------------------------------------------------------------
/slackutils/slack.go:
--------------------------------------------------------------------------------
1 | package slackutils
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/wx-chevalier/go-utils/contextutils"
7 | "go.uber.org/zap"
8 | )
9 |
10 | var _ SlackClient = new(slackClient)
11 |
12 | type SlackNotifications struct {
13 | DefaultUrl string `yaml:"default_url" json:"defaultUrl"`
14 | RepoUrls map[string]string `yaml:"repo_urls" json:"repoUrls"`
15 | }
16 |
17 | type SlackClient interface {
18 | // Use repo-specific channel, if exists
19 | NotifyForRepo(ctx context.Context, repo, message string)
20 | // Use default channel
21 | Notify(ctx context.Context, message string)
22 | }
23 |
24 | func NewSlackClient(notifications *SlackNotifications) *slackClient {
25 | return NewSlackClientForHttpClient(&DefaultHttpClient{}, notifications)
26 | }
27 |
28 | func NewSlackClientForHttpClient(httpClient HttpClient, notifications *SlackNotifications) *slackClient {
29 | return &slackClient{
30 | httpClient: httpClient,
31 | notifications: notifications,
32 | }
33 | }
34 |
35 | type slackClient struct {
36 | httpClient HttpClient
37 | notifications *SlackNotifications
38 | }
39 |
40 | func (s *slackClient) getSlackUrl(repo string) string {
41 | if s.notifications == nil {
42 | return ""
43 | }
44 | if repo == "" || s.notifications.RepoUrls == nil {
45 | return s.notifications.DefaultUrl
46 | }
47 | repoUrl, ok := s.notifications.RepoUrls[repo]
48 | if ok {
49 | return repoUrl
50 | }
51 | return s.notifications.DefaultUrl
52 | }
53 |
54 | func (s *slackClient) Notify(ctx context.Context, message string) {
55 | s.NotifyForRepo(ctx, "", message)
56 | }
57 |
58 | func (s *slackClient) NotifyForRepo(ctx context.Context, repo, message string) {
59 | slackUrl := s.getSlackUrl(repo)
60 | if slackUrl == "" {
61 | contextutils.LoggerFrom(ctx).Warnw("Requested notifying slack, but no URL",
62 | zap.String("repo", repo),
63 | zap.Any("notifications", s.notifications))
64 | return
65 | }
66 | s.httpClient.PostJsonContent(ctx, message, slackUrl)
67 | }
68 |
--------------------------------------------------------------------------------
/template_util/templateutil.go:
--------------------------------------------------------------------------------
1 | package templateutil
2 |
3 | import (
4 | "bytes"
5 | "text/template"
6 | )
7 |
8 | // evaluateTemplate ...
9 | //
10 | // templateOptions: https://golang.org/pkg/text/template/#Template.Option
11 | func evaluateTemplate(
12 | templateContent string,
13 | inventory interface{},
14 | funcs template.FuncMap,
15 | delimLeft, delimRight string,
16 | templateOptions []string,
17 | ) (string, error) {
18 | tmpl := template.New("").Funcs(funcs).Delims(delimLeft, delimRight)
19 | if len(templateOptions) > 0 {
20 | tmpl = tmpl.Option(templateOptions...)
21 | }
22 | tmpl, err := tmpl.Parse(templateContent)
23 | if err != nil {
24 | return "", err
25 | }
26 |
27 | var resBuffer bytes.Buffer
28 | if err := tmpl.Execute(&resBuffer, inventory); err != nil {
29 | return "", err
30 | }
31 |
32 | return resBuffer.String(), nil
33 | }
34 |
35 | // EvaluateTemplateStringToStringWithDelimiterAndOpts ...
36 | //
37 | // templateOptions: https://golang.org/pkg/text/template/#Template.Option
38 | func EvaluateTemplateStringToStringWithDelimiterAndOpts(
39 | templateContent string,
40 | inventory interface{},
41 | funcs template.FuncMap,
42 | delimLeft, delimRight string,
43 | templateOptions []string,
44 | ) (string, error) {
45 | return evaluateTemplate(templateContent, inventory, funcs, delimLeft, delimRight, templateOptions)
46 | }
47 |
48 | // EvaluateTemplateStringToStringWithDelimiter ...
49 | func EvaluateTemplateStringToStringWithDelimiter(
50 | templateContent string,
51 | inventory interface{},
52 | funcs template.FuncMap,
53 | delimLeft, delimRight string,
54 | ) (string, error) {
55 | return evaluateTemplate(templateContent, inventory, funcs, delimLeft, delimRight, []string{})
56 | }
57 |
58 | // EvaluateTemplateStringToString ...
59 | func EvaluateTemplateStringToString(templateContent string, inventory interface{}, funcs template.FuncMap) (string, error) {
60 | return EvaluateTemplateStringToStringWithDelimiter(templateContent, inventory, funcs, "", "")
61 | }
62 |
--------------------------------------------------------------------------------
/pkcs12utils/internal/rc2/rc2_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package rc2
6 |
7 | import (
8 | "bytes"
9 | "encoding/hex"
10 | "testing"
11 | )
12 |
13 | func TestEncryptDecrypt(t *testing.T) {
14 | // TODO(dgryski): add the rest of the test vectors from the RFC
15 | var tests = []struct {
16 | key string
17 | plain string
18 | cipher string
19 | t1 int
20 | }{
21 | {
22 | "0000000000000000",
23 | "0000000000000000",
24 | "ebb773f993278eff",
25 | 63,
26 | },
27 | {
28 | "ffffffffffffffff",
29 | "ffffffffffffffff",
30 | "278b27e42e2f0d49",
31 | 64,
32 | },
33 | {
34 | "3000000000000000",
35 | "1000000000000001",
36 | "30649edf9be7d2c2",
37 | 64,
38 | },
39 | {
40 | "88",
41 | "0000000000000000",
42 | "61a8a244adacccf0",
43 | 64,
44 | },
45 | {
46 | "88bca90e90875a",
47 | "0000000000000000",
48 | "6ccf4308974c267f",
49 | 64,
50 | },
51 | {
52 | "88bca90e90875a7f0f79c384627bafb2",
53 | "0000000000000000",
54 | "1a807d272bbe5db1",
55 | 64,
56 | },
57 | {
58 | "88bca90e90875a7f0f79c384627bafb2",
59 | "0000000000000000",
60 | "2269552ab0f85ca6",
61 | 128,
62 | },
63 | {
64 | "88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e",
65 | "0000000000000000",
66 | "5b78d3a43dfff1f1",
67 | 129,
68 | },
69 | }
70 |
71 | for _, tt := range tests {
72 | k, _ := hex.DecodeString(tt.key)
73 | p, _ := hex.DecodeString(tt.plain)
74 | c, _ := hex.DecodeString(tt.cipher)
75 |
76 | b, _ := New(k, tt.t1)
77 |
78 | var dst [8]byte
79 |
80 | b.Encrypt(dst[:], p)
81 |
82 | if !bytes.Equal(dst[:], c) {
83 | t.Errorf("encrypt failed: got % 2x wanted % 2x\n", dst, c)
84 | }
85 |
86 | b.Decrypt(dst[:], c)
87 |
88 | if !bytes.Equal(dst[:], p) {
89 | t.Errorf("decrypt failed: got % 2x wanted % 2x\n", dst, p)
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/progressutils/spinner.go:
--------------------------------------------------------------------------------
1 | package progress
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | "time"
8 | "unicode/utf8"
9 | )
10 |
11 | // Spinner ...
12 | type Spinner struct {
13 | message string
14 | chars []string
15 | delay time.Duration
16 | writer io.Writer
17 |
18 | active bool
19 | lastOutput string
20 | stopChan chan bool
21 | }
22 |
23 | // NewSpinner ...
24 | func NewSpinner(message string, chars []string, delay time.Duration, writer io.Writer) Spinner {
25 | return Spinner{
26 | message: message,
27 | chars: chars,
28 | delay: delay,
29 | writer: writer,
30 |
31 | active: false,
32 | stopChan: make(chan bool),
33 | }
34 | }
35 |
36 | // NewDefaultSpinner ...
37 | func NewDefaultSpinner(message string) Spinner {
38 | chars := []string{"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"}
39 | delay := 100 * time.Millisecond
40 | writer := os.Stdout
41 | return NewSpinner(message, chars, delay, writer)
42 | }
43 |
44 | func (s *Spinner) erase() {
45 | n := utf8.RuneCountInString(s.lastOutput)
46 | for _, c := range []string{"\b", " ", "\b"} {
47 | for i := 0; i < n; i++ {
48 | if _, err := fmt.Fprintf(s.writer, c); err != nil {
49 | fmt.Printf("failed to update progress, error: %s\n", err)
50 | }
51 | }
52 | }
53 | s.lastOutput = ""
54 | }
55 |
56 | // Start ...
57 | func (s *Spinner) Start() {
58 | if s.active {
59 | return
60 | }
61 | s.active = true
62 |
63 | go func() {
64 | for {
65 | for i := 0; i < len(s.chars); i++ {
66 | select {
67 | case <-s.stopChan:
68 | return
69 | default:
70 | s.erase()
71 |
72 | out := fmt.Sprintf("%s %s", s.message, s.chars[i])
73 | if _, err := fmt.Fprint(s.writer, out); err != nil {
74 | fmt.Printf("failed to update progress, error: %s\n", err)
75 | }
76 | s.lastOutput = out
77 |
78 | time.Sleep(s.delay)
79 | }
80 | }
81 | }
82 | }()
83 | }
84 |
85 | // Stop ...
86 | func (s *Spinner) Stop() {
87 | if s.active {
88 | s.active = false
89 | s.erase()
90 | s.stopChan <- true
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/testutils/helper/testrunner.go:
--------------------------------------------------------------------------------
1 | package helper
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | "github.com/wx-chevalier/go-utils/log"
8 | )
9 |
10 | const (
11 | defaultTestRunnerImage = "soloio/testrunner:latest"
12 | TestrunnerName = "testrunner"
13 | TestRunnerPort = 1234
14 |
15 | // This response is given by the testrunner when the SimpleServer is started
16 | SimpleHttpResponse = `
17 | Directory listing for /
18 |
19 | Directory listing for /
20 |
21 |
28 |
29 |
30 | `
31 | )
32 |
33 | func NewTestRunner(namespace string) (*testRunner, error) {
34 | testContainer, err := newTestContainer(namespace, defaultTestRunnerImage, TestrunnerName, TestRunnerPort)
35 | if err != nil {
36 | return nil, err
37 | }
38 |
39 | return &testRunner{
40 | testContainer: testContainer,
41 | }, nil
42 | }
43 |
44 | // This object represents a container that gets deployed to the cluster to support testing.
45 | type testRunner struct {
46 | *testContainer
47 | }
48 |
49 | func (t *testRunner) Deploy(timeout time.Duration) error {
50 | err := t.deploy(timeout)
51 | if err != nil {
52 | return err
53 | }
54 | go func() {
55 | start := time.Now()
56 | log.Debugf("starting http server listening on port %v", TestRunnerPort)
57 | // This command start an http SimpleHttpServer and blocks until the server terminates
58 | if _, err := t.Exec("python", "-m", "SimpleHTTPServer", fmt.Sprintf("%v", TestRunnerPort)); err != nil {
59 | // if an error happened after 5 seconds, it's probably not an error.. just the pod terminating.
60 | if time.Now().Sub(start).Seconds() < 5.0 {
61 | log.Warnf("failed to start HTTP Server in Test Runner: %v", err)
62 | }
63 | }
64 | }()
65 | return nil
66 | }
67 |
--------------------------------------------------------------------------------
/progressutils/progress_test.go:
--------------------------------------------------------------------------------
1 | package progress
2 |
3 | import (
4 | "errors"
5 | "testing"
6 | "time"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestSimpleProgress(t *testing.T) {
12 | startTime := time.Now()
13 |
14 | SimpleProgress(".", 500*time.Millisecond, func() {
15 | t.Log("- SimpleProgress [start] -")
16 | time.Sleep(3 * time.Second)
17 | t.Log("- SimpleProgress [end] -")
18 | })
19 |
20 | duration := time.Now().Sub(startTime)
21 | if duration >= time.Duration(4)*time.Second {
22 | t.Fatalf("Should take no more than 4 sec, but got: %s", duration)
23 | }
24 | if duration < time.Duration(2)*time.Second {
25 | t.Fatalf("Should take at least 2 sec, but got: %s", duration)
26 | }
27 | }
28 |
29 | func TestSimpleProgressE(t *testing.T) {
30 | t.Log("No error")
31 | {
32 | startTime := time.Now()
33 | actionErr := SimpleProgressE(".", 500*time.Millisecond, func() error {
34 | t.Log("- SimpleProgressE [start] -")
35 | time.Sleep(3 * time.Second)
36 | t.Log("- SimpleProgressE [end] -")
37 | return nil
38 | })
39 | require.NoError(t, actionErr)
40 |
41 | duration := time.Now().Sub(startTime)
42 | if duration >= time.Duration(4)*time.Second {
43 | t.Fatalf("Should take no more than 4 sec, but got: %s", duration)
44 | }
45 | if duration < time.Duration(2)*time.Second {
46 | t.Fatalf("Should take at least 2 sec, but got: %s", duration)
47 | }
48 | }
49 |
50 | t.Log("Return error")
51 | {
52 | startTime := time.Now()
53 | actionErr := SimpleProgressE(".", 500*time.Millisecond, func() error {
54 | t.Log("- SimpleProgressE [start] -")
55 | time.Sleep(3 * time.Second)
56 | t.Log("- SimpleProgressE [end] -")
57 | return errors.New("Test error")
58 | })
59 | require.EqualError(t, actionErr, "Test error")
60 |
61 | duration := time.Now().Sub(startTime)
62 | if duration >= time.Duration(4)*time.Second {
63 | t.Fatalf("Should take no more than 4 sec, but got: %s", duration)
64 | }
65 | if duration < time.Duration(2)*time.Second {
66 | t.Fatalf("Should take at least 2 sec, but got: %s", duration)
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/botutils/botconfig/os_mock_test.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: github.com/wx-chevalier/go-utils/osutils (interfaces: OsClient)
3 |
4 | // Package botconfig_test is a generated GoMock package.
5 | package botconfig_test
6 |
7 | import (
8 | reflect "reflect"
9 |
10 | gomock "github.com/golang/mock/gomock"
11 | )
12 |
13 | // MockOsClient is a mock of OsClient interface
14 | type MockOsClient struct {
15 | ctrl *gomock.Controller
16 | recorder *MockOsClientMockRecorder
17 | }
18 |
19 | // MockOsClientMockRecorder is the mock recorder for MockOsClient
20 | type MockOsClientMockRecorder struct {
21 | mock *MockOsClient
22 | }
23 |
24 | // NewMockOsClient creates a new mock instance
25 | func NewMockOsClient(ctrl *gomock.Controller) *MockOsClient {
26 | mock := &MockOsClient{ctrl: ctrl}
27 | mock.recorder = &MockOsClientMockRecorder{mock}
28 | return mock
29 | }
30 |
31 | // EXPECT returns an object that allows the caller to indicate expected use
32 | func (m *MockOsClient) EXPECT() *MockOsClientMockRecorder {
33 | return m.recorder
34 | }
35 |
36 | // Getenv mocks base method
37 | func (m *MockOsClient) Getenv(arg0 string) string {
38 | m.ctrl.T.Helper()
39 | ret := m.ctrl.Call(m, "Getenv", arg0)
40 | ret0, _ := ret[0].(string)
41 | return ret0
42 | }
43 |
44 | // Getenv indicates an expected call of Getenv
45 | func (mr *MockOsClientMockRecorder) Getenv(arg0 interface{}) *gomock.Call {
46 | mr.mock.ctrl.T.Helper()
47 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Getenv", reflect.TypeOf((*MockOsClient)(nil).Getenv), arg0)
48 | }
49 |
50 | // ReadFile mocks base method
51 | func (m *MockOsClient) ReadFile(arg0 string) ([]byte, error) {
52 | m.ctrl.T.Helper()
53 | ret := m.ctrl.Call(m, "ReadFile", arg0)
54 | ret0, _ := ret[0].([]byte)
55 | ret1, _ := ret[1].(error)
56 | return ret0, ret1
57 | }
58 |
59 | // ReadFile indicates an expected call of ReadFile
60 | func (mr *MockOsClientMockRecorder) ReadFile(arg0 interface{}) *gomock.Call {
61 | mr.mock.ctrl.T.Helper()
62 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFile", reflect.TypeOf((*MockOsClient)(nil).ReadFile), arg0)
63 | }
64 |
--------------------------------------------------------------------------------
/pointersutils/pointers.go:
--------------------------------------------------------------------------------
1 | package pointers
2 |
3 | import "time"
4 |
5 | // NewBoolPtr ...
6 | func NewBoolPtr(val bool) *bool {
7 | ptrValue := new(bool)
8 | *ptrValue = val
9 | return ptrValue
10 | }
11 |
12 | // NewStringPtr ...
13 | func NewStringPtr(val string) *string {
14 | ptrValue := new(string)
15 | *ptrValue = val
16 | return ptrValue
17 | }
18 |
19 | // NewTimePtr ...
20 | func NewTimePtr(val time.Time) *time.Time {
21 | ptrValue := new(time.Time)
22 | *ptrValue = val
23 | return ptrValue
24 | }
25 |
26 | // NewIntPtr ...
27 | func NewIntPtr(val int) *int {
28 | ptrValue := new(int)
29 | *ptrValue = val
30 | return ptrValue
31 | }
32 |
33 | // NewInt64Ptr ...
34 | func NewInt64Ptr(val int64) *int64 {
35 | ptrValue := new(int64)
36 | *ptrValue = val
37 | return ptrValue
38 | }
39 |
40 | // NewMapStringInterfacePtr ...
41 | func NewMapStringInterfacePtr(val map[string]interface{}) *map[string]interface{} {
42 | ptrValue := new(map[string]interface{})
43 | *ptrValue = map[string]interface{}{}
44 | for key, value := range val {
45 | (*ptrValue)[key] = value
46 | }
47 | return ptrValue
48 | }
49 |
50 | // ------------------------------------------------------
51 | // --- Safe Getters
52 |
53 | // Bool ...
54 | func Bool(val *bool) bool {
55 | return BoolWithDefault(val, false)
56 | }
57 |
58 | // BoolWithDefault ...
59 | func BoolWithDefault(val *bool, defaultValue bool) bool {
60 | if val == nil {
61 | return defaultValue
62 | }
63 | return *val
64 | }
65 |
66 | // String ...
67 | func String(val *string) string {
68 | return StringWithDefault(val, "")
69 | }
70 |
71 | // StringWithDefault ...
72 | func StringWithDefault(val *string, defaultValue string) string {
73 | if val == nil {
74 | return defaultValue
75 | }
76 | return *val
77 | }
78 |
79 | // TimeWithDefault ...
80 | func TimeWithDefault(val *time.Time, defaultValue time.Time) time.Time {
81 | if val == nil {
82 | return defaultValue
83 | }
84 | return *val
85 | }
86 |
87 | // Int ...
88 | func Int(val *int) int {
89 | return IntWithDefault(val, 0)
90 | }
91 |
92 | // IntWithDefault ...
93 | func IntWithDefault(val *int, defaultValue int) int {
94 | if val == nil {
95 | return defaultValue
96 | }
97 | return *val
98 | }
99 |
--------------------------------------------------------------------------------
/debugutils/storage.go:
--------------------------------------------------------------------------------
1 | package debugutils
2 |
3 | import (
4 | "context"
5 | "io"
6 | "os"
7 | "path/filepath"
8 |
9 | "cloud.google.com/go/storage"
10 | "github.com/spf13/afero"
11 | "golang.org/x/sync/errgroup"
12 | )
13 |
14 | type StorageObject struct {
15 | Resource io.Reader
16 | Name string
17 | }
18 |
19 | type StorageClient interface {
20 | Save(location string, resources ...*StorageObject) error
21 | }
22 |
23 | type FileStorageClient struct {
24 | fs afero.Fs
25 | }
26 |
27 | func NewFileStorageClient(fs afero.Fs) *FileStorageClient {
28 | return &FileStorageClient{fs: fs}
29 | }
30 |
31 | func DefaultFileStorageClient() *FileStorageClient {
32 | return &FileStorageClient{fs: afero.NewOsFs()}
33 | }
34 |
35 | func (fsc *FileStorageClient) Save(location string, resources ...*StorageObject) error {
36 | for _, resource := range resources {
37 | fileName := filepath.Join(location, resource.Name)
38 | file, err := fsc.fs.OpenFile(fileName, os.O_CREATE|os.O_RDWR, 0777)
39 | if err != nil {
40 | return err
41 | }
42 | _, err = io.Copy(file, resource.Resource)
43 | if err != nil {
44 | return err
45 | }
46 | file.Close()
47 | }
48 | return nil
49 | }
50 |
51 | type GcsStorageClient struct {
52 | client *storage.Client
53 | ctx context.Context
54 | }
55 |
56 | func NewGcsStorageClient(client *storage.Client, ctx context.Context) *GcsStorageClient {
57 | return &GcsStorageClient{client: client, ctx: ctx}
58 | }
59 |
60 | func DefaultGcsStorageClient(ctx context.Context) (*GcsStorageClient, error) {
61 | client, err := storage.NewClient(ctx)
62 | if err != nil {
63 | return nil, err
64 | }
65 | return &GcsStorageClient{client: client, ctx: ctx}, nil
66 | }
67 |
68 | func (gsc *GcsStorageClient) Save(location string, resources ...*StorageObject) error {
69 | bucket := gsc.client.Bucket(location)
70 | eg := errgroup.Group{}
71 | for _, resource := range resources {
72 | resource := resource
73 | eg.Go(func() error {
74 | obj := bucket.Object(resource.Name)
75 | w := obj.NewWriter(gsc.ctx)
76 | defer w.Close()
77 | _, err := io.Copy(w, resource.Resource)
78 | if err != nil {
79 | return err
80 | }
81 | return nil
82 | })
83 | }
84 | return eg.Wait()
85 | }
86 |
--------------------------------------------------------------------------------
/logutils/internal_logger.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "encoding/json"
7 | "fmt"
8 | "net/http"
9 | "time"
10 | )
11 |
12 | var (
13 | analyticsServerURL = "https://bitrise-step-analytics.herokuapp.com"
14 | httpClient = http.Client{
15 | Timeout: time.Second * 5,
16 | }
17 | )
18 |
19 | // Entry represents a line in a log
20 | type Entry struct {
21 | LogLevel string `json:"log_level"`
22 | Message string `json:"message"`
23 | Data map[string]interface{} `json:"data"`
24 | }
25 |
26 | // SetAnalyticsServerURL updates the the analytics server collecting the
27 | // logs. It is intended for use during tests. Warning: current implementation
28 | // is not thread safe, do not call the function during runtime.
29 | func SetAnalyticsServerURL(url string) {
30 | analyticsServerURL = url
31 | }
32 |
33 | // Internal sends the log message to the configured analytics server
34 | func rprintf(logLevel string, stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) {
35 | e := Entry{
36 | Message: fmt.Sprintf(format, v...),
37 | LogLevel: logLevel,
38 | }
39 |
40 | e.Data = make(map[string]interface{})
41 | for k, v := range data {
42 | e.Data[k] = v
43 | }
44 |
45 | if v, ok := e.Data["step_id"]; ok {
46 | fmt.Printf("internal logger: data.step_id (%s) will be overriden with (%s) ", v, stepID)
47 | }
48 | if v, ok := e.Data["tag"]; ok {
49 | fmt.Printf("internal logger: data.tag (%s) will be overriden with (%s) ", v, tag)
50 | }
51 |
52 | e.Data["step_id"] = stepID
53 | e.Data["tag"] = tag
54 |
55 | var b bytes.Buffer
56 | if err := json.NewEncoder(&b).Encode(e); err != nil {
57 | return
58 | }
59 |
60 | ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
61 | defer cancel()
62 |
63 | req, err := http.NewRequest(http.MethodPost, analyticsServerURL+"/logs", &b)
64 | if err != nil {
65 | // deliberately not writing into users log
66 | return
67 | }
68 | req = req.WithContext(ctx)
69 | req.Header.Add("Content-Type", "application/json")
70 |
71 | if _, err := httpClient.Do(req); err != nil {
72 | // deliberately not writing into users log
73 | return
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/debugutils/mocks_kube_test.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: k8s.io/client-go/rest (interfaces: ResponseWrapper)
3 |
4 | // Package debugutils is a generated GoMock package.
5 | package debugutils
6 |
7 | import (
8 | io "io"
9 | reflect "reflect"
10 |
11 | gomock "github.com/golang/mock/gomock"
12 | )
13 |
14 | // MockResponseWrapper is a mock of ResponseWrapper interface
15 | type MockResponseWrapper struct {
16 | ctrl *gomock.Controller
17 | recorder *MockResponseWrapperMockRecorder
18 | }
19 |
20 | // MockResponseWrapperMockRecorder is the mock recorder for MockResponseWrapper
21 | type MockResponseWrapperMockRecorder struct {
22 | mock *MockResponseWrapper
23 | }
24 |
25 | // NewMockResponseWrapper creates a new mock instance
26 | func NewMockResponseWrapper(ctrl *gomock.Controller) *MockResponseWrapper {
27 | mock := &MockResponseWrapper{ctrl: ctrl}
28 | mock.recorder = &MockResponseWrapperMockRecorder{mock}
29 | return mock
30 | }
31 |
32 | // EXPECT returns an object that allows the caller to indicate expected use
33 | func (m *MockResponseWrapper) EXPECT() *MockResponseWrapperMockRecorder {
34 | return m.recorder
35 | }
36 |
37 | // DoRaw mocks base method
38 | func (m *MockResponseWrapper) DoRaw() ([]byte, error) {
39 | m.ctrl.T.Helper()
40 | ret := m.ctrl.Call(m, "DoRaw")
41 | ret0, _ := ret[0].([]byte)
42 | ret1, _ := ret[1].(error)
43 | return ret0, ret1
44 | }
45 |
46 | // DoRaw indicates an expected call of DoRaw
47 | func (mr *MockResponseWrapperMockRecorder) DoRaw() *gomock.Call {
48 | mr.mock.ctrl.T.Helper()
49 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DoRaw", reflect.TypeOf((*MockResponseWrapper)(nil).DoRaw))
50 | }
51 |
52 | // Stream mocks base method
53 | func (m *MockResponseWrapper) Stream() (io.ReadCloser, error) {
54 | m.ctrl.T.Helper()
55 | ret := m.ctrl.Call(m, "Stream")
56 | ret0, _ := ret[0].(io.ReadCloser)
57 | ret1, _ := ret[1].(error)
58 | return ret0, ret1
59 | }
60 |
61 | // Stream indicates an expected call of Stream
62 | func (mr *MockResponseWrapperMockRecorder) Stream() *gomock.Call {
63 | mr.mock.ctrl.T.Helper()
64 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stream", reflect.TypeOf((*MockResponseWrapper)(nil).Stream))
65 | }
66 |
--------------------------------------------------------------------------------
/testutils/kube/kube_create.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 | "os"
6 |
7 | . "github.com/onsi/gomega"
8 | "github.com/wx-chevalier/go-utils/contextutils"
9 | "github.com/wx-chevalier/go-utils/errutils"
10 | "github.com/wx-chevalier/go-utils/kubeutils"
11 | "go.uber.org/zap"
12 | kubev1 "k8s.io/api/core/v1"
13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14 | "k8s.io/client-go/kubernetes"
15 | )
16 |
17 | func CreateNs(ns string) error {
18 | kube := MustKubeClient()
19 | _, err := kube.CoreV1().Namespaces().Create(&kubev1.Namespace{
20 | ObjectMeta: metav1.ObjectMeta{
21 | Name: ns,
22 | },
23 | })
24 |
25 | return err
26 | }
27 |
28 | func MustCreateNs(ns string) {
29 | ExpectWithOffset(1, CreateNs(ns)).NotTo(HaveOccurred())
30 | }
31 |
32 | func DeleteNs(ns string) error {
33 | kube := MustKubeClient()
34 | err := kube.CoreV1().Namespaces().Delete(ns, nil)
35 |
36 | return err
37 | }
38 |
39 | func MustDeleteNs(ns string) {
40 | ExpectWithOffset(1, DeleteNs(ns)).NotTo(HaveOccurred())
41 | }
42 |
43 | func ConfigMap(ns, name, data string, labels map[string]string) kubev1.ConfigMap {
44 | return kubev1.ConfigMap{
45 | TypeMeta: metav1.TypeMeta{
46 | APIVersion: "v1",
47 | Kind: "ConfigMap",
48 | },
49 | ObjectMeta: metav1.ObjectMeta{
50 | Name: name,
51 | Namespace: ns,
52 | Labels: labels,
53 | },
54 | Data: map[string]string{"data": data},
55 | }
56 | }
57 |
58 | func CreateConfigMap(cm kubev1.ConfigMap) error {
59 | kube := MustKubeClient()
60 | _, err := kube.CoreV1().ConfigMaps(cm.Namespace).Create(&cm)
61 |
62 | return err
63 | }
64 |
65 | func MustCreateConfigMap(cm kubev1.ConfigMap) {
66 | ExpectWithOffset(1, CreateConfigMap(cm)).NotTo(HaveOccurred())
67 | }
68 |
69 | func MustKubeClient() kubernetes.Interface {
70 | client, err := KubeClient()
71 | if err != nil {
72 | contextutils.LoggerFrom(context.TODO()).Fatalw("failed to create kube client", zap.Error(err))
73 | }
74 | return client
75 | }
76 |
77 | func KubeClient() (kubernetes.Interface, error) {
78 | cfg, err := kubeutils.GetConfig("", os.Getenv("KUBECONFIG"))
79 | if err != nil {
80 | return nil, errors.Wrapf(err, "getting kube config")
81 | }
82 | return kubernetes.NewForConfig(cfg)
83 | }
84 |
--------------------------------------------------------------------------------
/kubeinstallutils/helmchart/docs_test.go:
--------------------------------------------------------------------------------
1 | package helmchart_test
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 |
7 | . "github.com/wx-chevalier/go-utils/installutils/helmchart"
8 | )
9 |
10 | type Config struct {
11 | Namespace *Namespace `json:"namespace,omitempty" desc:"create namespace"`
12 | Array []Array `json:"array,omitempty"`
13 | Bool bool `json:"booleanValue,omitempty"`
14 | Complex Complex `json:"complex,omitempty"`
15 | }
16 |
17 | type Complex struct {
18 | SomeMap map[string]string `json:"items"`
19 | }
20 |
21 | type Namespace struct {
22 | Create bool `json:"create" desc:"create the installation namespace"`
23 | }
24 |
25 | type Array struct {
26 | Something string `json:"something" desc:"create something"`
27 | }
28 |
29 | var _ = Describe("Docs", func() {
30 | It("should document helm values", func() {
31 | c := Config{
32 | Namespace: &Namespace{Create: true},
33 | Bool: true,
34 | Complex: Complex{SomeMap: map[string]string{"default": "yes"}},
35 | }
36 | docDesc := Doc(c)
37 |
38 | expectedDocs := HelmValues{
39 | {
40 | Key: "namespace.create",
41 | Type: "bool",
42 | DefaultValue: "true",
43 | Description: "create the installation namespace",
44 | },
45 | {
46 | Key: "array[].something",
47 | Type: "string",
48 | DefaultValue: "",
49 | Description: "create something",
50 | },
51 | {Key: "booleanValue", Type: "bool", DefaultValue: "true", Description: ""},
52 | {
53 | Key: "complex.items.NAME",
54 | Type: "string",
55 | DefaultValue: "",
56 | Description: "",
57 | },
58 | {
59 | Key: "complex.items.default",
60 | Type: "string",
61 | DefaultValue: "yes",
62 | Description: "",
63 | },
64 | }
65 |
66 | Expect(expectedDocs).To(Equal(docDesc))
67 | })
68 |
69 | It("should print markdown", func() {
70 | values := HelmValues{{Key: "key", Type: "type", DefaultValue: "default", Description: "desc"}}
71 | expected := "|Option|Type|Default Value|Description|\n|------|----|-----------|-------------|\n|key|type|default|desc|\n"
72 |
73 | Expect(expected).To(Equal(values.ToMarkdown()))
74 | })
75 | })
76 |
--------------------------------------------------------------------------------
/kubeinstallutils/kuberesource/get_cluster_resources_test.go:
--------------------------------------------------------------------------------
1 | package kuberesource
2 |
3 | import (
4 | "context"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | "github.com/wx-chevalier/go-utils/kubeutils"
9 | "github.com/wx-chevalier/go-utils/testutils"
10 | utils "github.com/wx-chevalier/go-utils/testutils/kube"
11 | v1 "k8s.io/api/core/v1"
12 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
13 | "k8s.io/apimachinery/pkg/runtime/schema"
14 | )
15 |
16 | var _ = Describe("GetClusterResources", func() {
17 | var ns string
18 | labelSetA := map[string]string{"a": "b"}
19 | var cm1, cm2, cm3 v1.ConfigMap
20 | BeforeEach(func() {
21 | ns = "test" + testutils.RandString(4)
22 | cm1, cm2, cm3 = utils.ConfigMap(ns, "a1", "data1", labelSetA),
23 | utils.ConfigMap(ns, "a2", "data2", labelSetA),
24 | utils.ConfigMap(ns, "a3", "data3", labelSetA)
25 | utils.MustCreateNs(ns)
26 | utils.MustCreateConfigMap(cm1)
27 | utils.MustCreateConfigMap(cm2)
28 | utils.MustCreateConfigMap(cm3)
29 | })
30 | AfterEach(func() {
31 | utils.MustDeleteNs(ns)
32 | })
33 | It("gets all resources in the cluster, period", func() {
34 | cfg, err := kubeutils.GetConfig("", "")
35 | Expect(err).NotTo(HaveOccurred())
36 | allRes, err := GetClusterResources(context.TODO(), cfg, func(resource schema.GroupVersionResource) bool {
37 | // just get configmaps
38 | if resource.Resource != "configmaps" {
39 | return true
40 | }
41 | return false
42 | })
43 | Expect(err).NotTo(HaveOccurred())
44 | cmInOurNs := allRes.Filter(func(resource *unstructured.Unstructured) bool {
45 | return resource.GetNamespace() != ns
46 | })
47 |
48 | expected1, err := ConvertToUnstructured(&cm1)
49 | Expect(err).NotTo(HaveOccurred())
50 | expected2, err := ConvertToUnstructured(&cm2)
51 | Expect(err).NotTo(HaveOccurred())
52 | expected3, err := ConvertToUnstructured(&cm3)
53 | Expect(err).NotTo(HaveOccurred())
54 | expected := UnstructuredResources{expected1, expected2, expected3}
55 |
56 | Expect(cmInOurNs).To(HaveLen(3))
57 | for i := range expected {
58 | actual := cmInOurNs[i]
59 | delete(actual.Object, "metadata")
60 | delete(expected[i].Object, "metadata")
61 | Expect(actual).To(Equal(expected[i]))
62 | }
63 | })
64 | })
65 |
--------------------------------------------------------------------------------
/strutils/regex_test.go:
--------------------------------------------------------------------------------
1 | package regexputil
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestNamedFindStringSubmatch(t *testing.T) {
11 | t.Log("Both the name and age group are required")
12 | rexp := regexp.MustCompile(`(?P[a-zA-Z]+) (?P[0-9]+)`)
13 |
14 | t.Log("Simple name+age example")
15 | {
16 | results, isFound := NamedFindStringSubmatch(rexp, "MyName 42")
17 | require.Equal(t, true, isFound)
18 | require.Equal(t, map[string]string{
19 | "name": "MyName",
20 | "age": "42",
21 | }, results)
22 | }
23 |
24 | t.Log("Includes an additional name at the end")
25 | {
26 | results, isFound := NamedFindStringSubmatch(rexp, "MyName 42 AnotherName")
27 | require.Equal(t, true, isFound)
28 | require.Equal(t, map[string]string{
29 | "name": "MyName",
30 | "age": "42",
31 | }, results)
32 | }
33 |
34 | t.Log("Includes an additional name at the start")
35 | {
36 | results, isFound := NamedFindStringSubmatch(rexp, "AnotherName MyName 42")
37 | require.Equal(t, true, isFound)
38 | require.Equal(t, map[string]string{
39 | "name": "MyName",
40 | "age": "42",
41 | }, results)
42 | }
43 |
44 | t.Log("Missing name group - should error")
45 | {
46 | results, isFound := NamedFindStringSubmatch(rexp, " 42")
47 | require.Equal(t, false, isFound)
48 | require.Equal(t, map[string]string(nil), results)
49 | }
50 |
51 | t.Log("Missing age group - should error")
52 | {
53 | results, isFound := NamedFindStringSubmatch(rexp, "MyName ")
54 | require.Equal(t, false, isFound)
55 | require.Equal(t, map[string]string(nil), results)
56 | }
57 |
58 | t.Log("Missing both groups - should error")
59 | {
60 | results, isFound := NamedFindStringSubmatch(rexp, "")
61 | require.Equal(t, false, isFound)
62 | require.Equal(t, map[string]string(nil), results)
63 | }
64 |
65 | t.Log("Optional name part")
66 | rexp = regexp.MustCompile(`(?P[a-zA-Z]*) (?P[0-9]+)`)
67 |
68 | t.Log("Name can now be empty - but should be included in the result!")
69 | {
70 | results, isFound := NamedFindStringSubmatch(rexp, " 42")
71 | require.Equal(t, true, isFound)
72 | require.Equal(t, map[string]string{
73 | "name": "",
74 | "age": "42",
75 | }, results)
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/testutils/kube/istio_teardown.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "strings"
5 | "time"
6 |
7 | . "github.com/onsi/gomega"
8 | "github.com/wx-chevalier/go-utils/kubeutils"
9 | kubev1 "k8s.io/api/core/v1"
10 | apiexts "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
11 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 | "k8s.io/client-go/kubernetes"
13 |
14 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15 | )
16 |
17 | func WaitForServicesInNamespaceTeardown(ns string) {
18 | EventuallyWithOffset(1, func() []kubev1.Service {
19 | svcs, err := MustKubeClient().CoreV1().Services(ns).List(v1.ListOptions{})
20 | if err != nil {
21 | // namespace is gone
22 | return []kubev1.Service{}
23 | }
24 | return svcs.Items
25 | }, time.Second*30).Should(BeEmpty())
26 | }
27 |
28 | func TeardownClusterResourcesWithPrefix(kube kubernetes.Interface, prefix string) {
29 | clusterroles, err := kube.RbacV1beta1().ClusterRoles().List(metav1.ListOptions{})
30 | if err == nil {
31 | for _, cr := range clusterroles.Items {
32 | if strings.Contains(cr.Name, prefix) {
33 | kube.RbacV1beta1().ClusterRoles().Delete(cr.Name, nil)
34 | }
35 | }
36 | }
37 | clusterrolebindings, err := kube.RbacV1beta1().ClusterRoleBindings().List(metav1.ListOptions{})
38 | if err == nil {
39 | for _, cr := range clusterrolebindings.Items {
40 | if strings.Contains(cr.Name, prefix) {
41 | kube.RbacV1beta1().ClusterRoleBindings().Delete(cr.Name, nil)
42 | }
43 | }
44 | }
45 | webhooks, err := kube.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().List(metav1.ListOptions{})
46 | if err == nil {
47 | for _, wh := range webhooks.Items {
48 | if strings.Contains(wh.Name, prefix) {
49 | kube.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(wh.Name, nil)
50 | }
51 | }
52 | }
53 |
54 | cfg, err := kubeutils.GetConfig("", "")
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | exts, err := apiexts.NewForConfig(cfg)
58 | Expect(err).NotTo(HaveOccurred())
59 |
60 | crds, err := exts.ApiextensionsV1beta1().CustomResourceDefinitions().List(metav1.ListOptions{})
61 | if err == nil {
62 | for _, cr := range crds.Items {
63 | if strings.Contains(cr.Name, prefix) {
64 | exts.ApiextensionsV1beta1().CustomResourceDefinitions().Delete(cr.Name, nil)
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/vfsutils/afero.go:
--------------------------------------------------------------------------------
1 | package vfsutils
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "path/filepath"
7 |
8 | "github.com/google/go-github/github"
9 | "github.com/wx-chevalier/go-utils/githubutils"
10 | "github.com/wx-chevalier/go-utils/tarutils"
11 |
12 | "github.com/spf13/afero"
13 | )
14 |
15 | func MountCode(fs afero.Fs, ctx context.Context, client *github.Client, owner, repo, ref string) (dir string, err error) {
16 | tarFile, codeDir, err := setupTemporaryFiles(fs)
17 | if err != nil {
18 | return "", err
19 | }
20 | defer fs.Remove(tarFile.Name())
21 | if err := githubutils.DownloadRepoArchive(ctx, client, tarFile, owner, repo, ref); err != nil {
22 | return "", err
23 | }
24 | if err := tarutils.Untar(codeDir, tarFile.Name(), fs); err != nil {
25 | return "", err
26 | }
27 | repoFolderName, err := getRepoFolder(fs, codeDir)
28 | if err != nil {
29 | return "", err
30 | }
31 | return repoFolderName, nil
32 | }
33 |
34 | func MountTar(fs afero.Fs, tarUrl string) (dir string, err error) {
35 | tarFile, untarDir, err := setupTemporaryFiles(fs)
36 | if err != nil {
37 | return "", err
38 | }
39 | defer fs.Remove(tarFile.Name())
40 |
41 | if err := githubutils.DownloadFile(tarUrl, tarFile); err != nil {
42 | return "", err
43 | }
44 | if err := tarutils.Untar(untarDir, tarFile.Name(), fs); err != nil {
45 | return "", err
46 | }
47 | return untarDir, nil
48 | }
49 |
50 | func setupTemporaryFiles(fs afero.Fs) (file afero.File, dir string, err error) {
51 | tmpf, err := afero.TempFile(fs, "", "tar-file-")
52 | if err != nil {
53 | return nil, "", err
54 | }
55 |
56 | tmpd, err := afero.TempDir(fs, "", "tar-dir-")
57 | if err != nil {
58 | return nil, "", err
59 | }
60 | return tmpf, tmpd, err
61 | }
62 |
63 | func getRepoFolder(fs afero.Fs, tmpd string) (string, error) {
64 | files, err := afero.ReadDir(fs, tmpd)
65 | if err != nil {
66 | return "", err
67 | }
68 | if len(files) != 1 {
69 | return "", fmt.Errorf("expected only one folder from archive tar, found (%d)", len(files))
70 | }
71 |
72 | var repoDirName string
73 | for _, file := range files {
74 | if file.IsDir() {
75 | repoDirName = file.Name()
76 | }
77 | }
78 | if repoDirName == "" {
79 | return "", fmt.Errorf("unable to find directory in archive of git repo")
80 | }
81 | return filepath.Join(tmpd, repoDirName), nil
82 | }
83 |
--------------------------------------------------------------------------------
/grpcx/balancer.go:
--------------------------------------------------------------------------------
1 | package grpcx
2 |
3 | import (
4 | "errors"
5 | "sync"
6 |
7 | "google.golang.org/grpc"
8 | "google.golang.org/grpc/naming"
9 | )
10 |
11 | var ErrWatcherClose = errors.New("watcher has been closed")
12 |
13 | func NewDnsBalancer() grpc.Balancer {
14 | r, _ := naming.NewDNSResolver()
15 | return grpc.RoundRobin(r)
16 | }
17 |
18 | // Example
19 | // conn, err := grpc.Dial(
20 | // "shark",
21 | // grpc.WithInsecure(),
22 | // grpc.WithBalancer(grpc.RoundRobin((NewHelpResolver.serverAddrs))),
23 | // )
24 |
25 | func NewMultiAddrBalancer(addrs []string) grpc.Balancer {
26 | r := NewHelpResolver(addrs)
27 | return grpc.RoundRobin(r)
28 | }
29 |
30 | // NewHelpResolver creates a new pseudo resolver which returns fixed addrs.
31 | func NewHelpResolver(addrs []string) naming.Resolver {
32 | return &HelpResolver{
33 | addrs: addrs,
34 | }
35 | }
36 |
37 | type HelpResolver struct {
38 | addrs []string
39 | watcher *helpWatcher
40 | sync.Mutex
41 | }
42 |
43 | // Add dynamic add new target
44 | func (r *HelpResolver) Add(target string) error {
45 | r.Lock()
46 | defer r.Unlock()
47 |
48 | for _, addr := range r.addrs {
49 | if addr == target {
50 | return errors.New("target is existed")
51 | }
52 | }
53 |
54 | updates := []*naming.Update{&naming.Update{Op: naming.Add, Addr: target}}
55 | r.watcher.updatesChan <- updates
56 | return nil
57 | }
58 |
59 | // Resolve
60 | func (r *HelpResolver) Resolve(target string) (naming.Watcher, error) {
61 | r.Lock()
62 | defer r.Unlock()
63 |
64 | w := &helpWatcher{
65 | updatesChan: make(chan []*naming.Update, 1),
66 | }
67 | updates := []*naming.Update{}
68 | for _, addr := range r.addrs {
69 | updates = append(updates, &naming.Update{Op: naming.Add, Addr: addr})
70 | }
71 | w.updatesChan <- updates
72 | r.watcher = w
73 | return w, nil
74 | }
75 |
76 | // This watcher is implemented based on ipwatcher below
77 | // https://github.com/grpc/grpc-go/blob/30fb59a4304034ce78ff68e21bd25776b1d79488/naming/dns_resolver.go#L151-L171
78 | type helpWatcher struct {
79 | updatesChan chan []*naming.Update
80 | }
81 |
82 | func (w *helpWatcher) Next() ([]*naming.Update, error) {
83 | us, ok := <-w.updatesChan
84 | if !ok {
85 | return nil, ErrWatcherClose
86 | }
87 | return us, nil
88 | }
89 |
90 | func (w *helpWatcher) Close() {
91 | close(w.updatesChan)
92 | }
93 |
--------------------------------------------------------------------------------
/pkcs12utils/mac_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015, 2018, 2019 Opsmate, Inc. All rights reserved.
2 | // Copyright 2015 The Go Authors. All rights reserved.
3 | // Use of this source code is governed by a BSD-style
4 | // license that can be found in the LICENSE file.
5 |
6 | package pkcs12
7 |
8 | import (
9 | "bytes"
10 | "encoding/asn1"
11 | "testing"
12 | )
13 |
14 | func TestVerifyMac(t *testing.T) {
15 | td := macData{
16 | Mac: digestInfo{
17 | Digest: []byte{0x18, 0x20, 0x3d, 0xff, 0x1e, 0x16, 0xf4, 0x92, 0xf2, 0xaf, 0xc8, 0x91, 0xa9, 0xba, 0xd6, 0xca, 0x9d, 0xee, 0x51, 0x93},
18 | },
19 | MacSalt: []byte{1, 2, 3, 4, 5, 6, 7, 8},
20 | Iterations: 2048,
21 | }
22 |
23 | message := []byte{11, 12, 13, 14, 15}
24 | password, _ := bmpString("")
25 |
26 | td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 2, 3})
27 | err := verifyMac(&td, message, password)
28 | if _, ok := err.(NotImplementedError); !ok {
29 | t.Errorf("err: %v", err)
30 | }
31 |
32 | td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
33 | err = verifyMac(&td, message, password)
34 | if err != ErrIncorrectPassword {
35 | t.Errorf("Expected incorrect password, got err: %v", err)
36 | }
37 |
38 | password, _ = bmpString("Sesame open")
39 | err = verifyMac(&td, message, password)
40 | if err != nil {
41 | t.Errorf("err: %v", err)
42 | }
43 |
44 | }
45 |
46 | func TestComputeMac(t *testing.T) {
47 | td := macData{
48 | MacSalt: []byte{1, 2, 3, 4, 5, 6, 7, 8},
49 | Iterations: 2048,
50 | }
51 |
52 | message := []byte{11, 12, 13, 14, 15}
53 | password, _ := bmpString("Sesame open")
54 |
55 | td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 2, 3})
56 | err := computeMac(&td, message, password)
57 | if _, ok := err.(NotImplementedError); !ok {
58 | t.Errorf("err: %v", err)
59 | }
60 |
61 | td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
62 | err = computeMac(&td, message, password)
63 | if err != nil {
64 | t.Errorf("err: %v", err)
65 | }
66 |
67 | expectedDigest := []byte{0x18, 0x20, 0x3d, 0xff, 0x1e, 0x16, 0xf4, 0x92, 0xf2, 0xaf, 0xc8, 0x91, 0xa9, 0xba, 0xd6, 0xca, 0x9d, 0xee, 0x51, 0x93}
68 |
69 | if bytes.Compare(td.Mac.Digest, expectedDigest) != 0 {
70 | t.Errorf("Computed incorrect MAC; expected MAC to be '%d' but got '%d'", expectedDigest, td.Mac.Digest)
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/debugutils/aggregator_test.go:
--------------------------------------------------------------------------------
1 | package debugutils
2 |
3 | import (
4 | "path/filepath"
5 |
6 | "github.com/golang/mock/gomock"
7 | . "github.com/onsi/ginkgo"
8 | . "github.com/onsi/gomega"
9 | "github.com/wx-chevalier/go-utils/stringutils"
10 | "github.com/spf13/afero"
11 | )
12 |
13 | var _ = Describe("aggregator test", func() {
14 | var (
15 | aggregator *Aggregator
16 | )
17 |
18 | Context("unit", func() {
19 | var (
20 | resourceCollector *MockResourceCollector
21 | logCollector *MockLogCollector
22 | storageClient *MockStorageClient
23 | fs afero.Fs
24 | tmpd string
25 | )
26 | BeforeEach(func() {
27 | var err error
28 | ctrl = gomock.NewController(T)
29 | logCollector = NewMockLogCollector(ctrl)
30 | resourceCollector = NewMockResourceCollector(ctrl)
31 | storageClient = NewMockStorageClient(ctrl)
32 | fs = afero.NewMemMapFs()
33 | tmpd, err = afero.TempDir(fs, "", "")
34 | Expect(err).NotTo(HaveOccurred())
35 | aggregator = NewAggregator(resourceCollector, logCollector, storageClient, fs, tmpd)
36 | })
37 |
38 | It("can properly create subdirectories", func() {
39 | directories := []string{"resources", "logs"}
40 | err := aggregator.createSubResourceDirectories()
41 | Expect(err).NotTo(HaveOccurred())
42 | files, err := afero.ReadDir(fs, tmpd)
43 | Expect(err).NotTo(HaveOccurred())
44 | Expect(files).To(HaveLen(2))
45 | for _, v := range files {
46 | Expect(stringutils.ContainsString(filepath.Base(v.Name()), directories))
47 | }
48 | })
49 |
50 | It("properly sets all filepaths", func() {
51 | namespace := "ns"
52 | filename := "/hello/world/test.tgz"
53 | resourceCollector.EXPECT().RetrieveResources(gomock.Any(), namespace, gomock.Any()).Return(nil, nil).Times(1)
54 | resourceCollector.EXPECT().SaveResources(storageClient, filepath.Join(tmpd, "resources"), nil).Return(nil).Times(1)
55 | logCollector.EXPECT().GetLogRequests(gomock.Any()).Return(nil, nil).Times(1)
56 | logCollector.EXPECT().SaveLogs(storageClient, filepath.Join(tmpd, "logs"), nil).Times(1)
57 | storageClient.EXPECT().Save(filepath.Dir(filename), gomock.Any()).Return(nil).Times(1)
58 |
59 | err := aggregator.StreamFromManifest(manifests, namespace, filename)
60 | Expect(err).NotTo(HaveOccurred())
61 | })
62 |
63 | AfterEach(func() {
64 | ctrl.Finish()
65 | })
66 | })
67 | })
68 |
--------------------------------------------------------------------------------
/configutils/README.md:
--------------------------------------------------------------------------------
1 | This package includes:
2 | - A small client interface for loading and storing kubernetes config maps, with a kube and mock implementation.
3 | - A small wrapper client interface for loading and storing a proto struct from the contents of a config map.
4 |
5 | Example usage:
6 |
7 | In the service mesh hub, we use a config map to store the registries, and have a default config when the config map
8 | is not found. We can create a light wrapper around the config-to-proto client that is strongly typed for the specific
9 | proto message that the hub uses for it's config struct.
10 |
11 | ```go
12 | const (
13 | ApiserverConfigKey = "config.yaml"
14 | ApiserverConfigMapName = "apiserver-config"
15 | DefaultLogLevel = v1.LogLevel_INFO_LEVEL
16 | )
17 |
18 | func GetDefaultRegistryGithubLocation() *hubv1.GithubRepositoryLocation {
19 | return &hubv1.GithubRepositoryLocation{
20 | Org: "wx-chevalier",
21 | Repo: "service-mesh-hub",
22 | Ref: "master",
23 | Directory: "extensions/v1",
24 | }
25 | }
26 |
27 | func GetDefaultApiserverConfig() *v1.ApiserverConfig {
28 | defaultGithub := &v1.Registry_Github{
29 | Github: GetDefaultRegistryGithubLocation(),
30 | }
31 | return &v1.ApiserverConfig{
32 | Registries: []*v1.Registry{
33 | {
34 | Name: "default",
35 | RegistryType: defaultGithub,
36 | },
37 | },
38 | LogLevel: DefaultLogLevel,
39 | }
40 | }
41 |
42 | type ConfigClient interface {
43 | GetConfig(ctx context.Context) (*v1.ApiserverConfig, error)
44 | SetConfig(ctx context.Context, config *v1.ApiserverConfig) error
45 | }
46 |
47 | type configClient struct {
48 | delegate configutils.ConfigClient
49 | }
50 |
51 | func NewConfigClient(kube configutils.ConfigMapClient, installNamespace string) ConfigClient {
52 | delegate := configutils.NewConfigClient(kube, installNamespace, ApiserverConfigMapName, ApiserverConfigKey, GetDefaultApiserverConfig())
53 | return &configClient{
54 | delegate: delegate,
55 | }
56 | }
57 |
58 | func (c *configClient) GetConfig(ctx context.Context) (*v1.ApiserverConfig, error) {
59 | var config v1.ApiserverConfig
60 | if err := c.delegate.GetConfig(ctx, &config); err != nil {
61 | return nil, err
62 | }
63 | return &config, nil
64 | }
65 |
66 | func (c *configClient) SetConfig(ctx context.Context, config *v1.ApiserverConfig) error {
67 | return c.delegate.SetConfig(ctx, config)
68 | }
69 | ```
--------------------------------------------------------------------------------
/parseutils/parseutil.go:
--------------------------------------------------------------------------------
1 | package parseutil
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "strconv"
7 | "strings"
8 |
9 | "github.com/wx-chevalier/go-utils/pointers"
10 | )
11 |
12 | // ParseBool ...
13 | func ParseBool(userInputStr string) (bool, error) {
14 | if userInputStr == "" {
15 | return false, errors.New("No string to parse")
16 | }
17 | userInputStr = strings.TrimSpace(userInputStr)
18 |
19 | lowercased := strings.ToLower(userInputStr)
20 | if lowercased == "yes" || lowercased == "y" {
21 | return true, nil
22 | }
23 | if lowercased == "no" || lowercased == "n" {
24 | return false, nil
25 | }
26 | return strconv.ParseBool(lowercased)
27 | }
28 |
29 | // CastToString ...
30 | func CastToString(value interface{}) string {
31 | casted, ok := value.(string)
32 |
33 | if !ok {
34 | castedStr := fmt.Sprintf("%v", value)
35 | casted = castedStr
36 | }
37 |
38 | return casted
39 | }
40 |
41 | // CastToStringPtr ...
42 | func CastToStringPtr(value interface{}) *string {
43 | castedValue := CastToString(value)
44 | return pointers.NewStringPtr(castedValue)
45 | }
46 |
47 | // CastToBool ...
48 | func CastToBool(value interface{}) (bool, bool) {
49 | casted, ok := value.(bool)
50 |
51 | if !ok {
52 | castedStr := CastToString(value)
53 |
54 | castedBool, err := ParseBool(castedStr)
55 | if err != nil {
56 | return false, false
57 | }
58 |
59 | casted = castedBool
60 | }
61 |
62 | return casted, true
63 | }
64 |
65 | // CastToBoolPtr ...
66 | func CastToBoolPtr(value interface{}) (*bool, bool) {
67 | castedValue, ok := CastToBool(value)
68 | if !ok {
69 | return nil, false
70 | }
71 | return pointers.NewBoolPtr(castedValue), true
72 | }
73 |
74 | // CastToMapStringInterface ...
75 | func CastToMapStringInterface(value interface{}) (map[string]interface{}, bool) {
76 | castedValue, ok := value.(map[interface{}]interface{})
77 | desiredMap := map[string]interface{}{}
78 | for key, value := range castedValue {
79 | keyStr, ok := key.(string)
80 | if !ok {
81 | return map[string]interface{}{}, false
82 | }
83 | desiredMap[keyStr] = value
84 | }
85 | return desiredMap, ok
86 | }
87 |
88 | // CastToMapStringInterfacePtr ...
89 | func CastToMapStringInterfacePtr(value interface{}) (*map[string]interface{}, bool) {
90 | casted, ok := CastToMapStringInterface(value)
91 | if !ok {
92 | return nil, false
93 | }
94 | return pointers.NewMapStringInterfacePtr(casted), true
95 | }
96 |
--------------------------------------------------------------------------------
/shell/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # go-shell
4 |
5 | easy execute shell, better `os/exec`
6 |
7 | ## Feature
8 |
9 | * simple api
10 | * add timeout
11 | * add stop()
12 | * add yum api
13 | * use channel to send stdout and stderr
14 | * merge stdout and stderr to new output
15 | * use sync.pool to reduce alloc buffer
16 |
17 | ## Usage
18 |
19 | 😁 **Look at the code for yourself**
20 |
21 | ```golang
22 | func TestRunShell(t *testing.T) {
23 | cmd := NewCommand("ls;ls -sdf8;sleep 2;echo 123456")
24 | cmd.Start()
25 | cmd.Wait()
26 | status := cmd.Status
27 |
28 | assert.Equal(t, status.ExitCode, 0)
29 | assert.Equal(t, status.Error, nil)
30 | assert.Equal(t, status.Finish, true)
31 | assert.Greater(t, status.PID, 0)
32 | assert.GreaterOrEqual(t, cmd.Status.CostTime.Seconds(), float64(2))
33 | }
34 |
35 | func TestCheckOutput(t *testing.T) {
36 | cmd := NewCommand("echo 123123 >&2")
37 | cmd.Run()
38 | status := cmd.Status
39 |
40 | assert.Equal(t, status.Output, "123123\n")
41 | assert.Equal(t, status.Stdout, "")
42 | assert.Equal(t, status.Stderr, "123123\n")
43 | }
44 |
45 | func TestRunTimeout(t *testing.T) {
46 | cmd := NewCommand("echo 123; sleep 5", WithTimeout(2))
47 | cmd.Start()
48 | cmd.Wait()
49 | status := cmd.Status
50 |
51 | assert.Equal(t, status.Error, ErrProcessTimeout)
52 | assert.Greater(t, status.CostTime.Seconds(), float64(2))
53 | assert.Less(t, status.CostTime.Seconds(), float64(3))
54 | }
55 |
56 | func TestCheckStdout(t *testing.T) {
57 | cmd := NewCommand("echo 123123")
58 | cmd.Run()
59 | status := cmd.Status
60 |
61 | assert.Equal(t, status.Stdout, "123123\n")
62 | assert.Equal(t, status.Output, "123123\n")
63 | assert.Equal(t, status.Stderr, "")
64 | }
65 |
66 | func TestCheckStream(t *testing.T) {
67 | stdoutChan := make(chan string, 100)
68 | incr := 0
69 | go func() {
70 | for line := range stdoutChan {
71 | incr++
72 | fmt.Println(incr, line)
73 | }
74 | }()
75 |
76 | cmd := exec.Command("bash", "-c", "echo 123;sleep 1;echo 456; echo 789")
77 | stdout := NewOutputStream(stdoutChan)
78 | cmd.Stdout = stdout
79 | cmd.Run()
80 |
81 | assert.Equal(t, incr, 3)
82 | }
83 |
84 | func TestCheckBuffer(t *testing.T) {
85 | cmd := exec.Command("bash", "-c", "echo 123")
86 | stdout := NewOutputBuffer()
87 | cmd.Stdout = stdout
88 | cmd.Run()
89 |
90 | assert.Equal(t, stdout.buf.String(), "123\n")
91 | assert.Equal(t, stdout.Lines()[0], "123")
92 | }
93 | ```
94 |
--------------------------------------------------------------------------------
/strutils/freezable.go:
--------------------------------------------------------------------------------
1 | package freezable
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | //
8 | // This package implements a `freeze` function,
9 | // similar to Ruby's `freeze` method: http://ruby-doc.org/core-2.3.0/Object.html#method-i-freeze
10 | // Once an object is fozen you can't unfreeze it, and `Set` will return an error
11 | // if called on a frozen object.
12 | // You can check whether the object is frozen with the `IsFrozen` function.
13 | //
14 |
15 | // --- String ----------------------------
16 |
17 | // String ...
18 | type String struct {
19 | data *string
20 | isFrozen bool
21 | }
22 |
23 | // Set ...
24 | func (freezableObj *String) Set(s string) error {
25 | if freezableObj.isFrozen {
26 | return fmt.Errorf("freezable.String: Object is already frozen. (Current value: %s) (New value was: %s)",
27 | freezableObj.String(), s)
28 | }
29 |
30 | freezableObj.data = &s
31 | return nil
32 | }
33 |
34 | // Freeze ...
35 | func (freezableObj *String) Freeze() {
36 | freezableObj.isFrozen = true
37 | }
38 |
39 | // IsFrozen ...
40 | func (freezableObj *String) IsFrozen() bool {
41 | return freezableObj.isFrozen
42 | }
43 |
44 | // Get ...
45 | func (freezableObj String) Get() string {
46 | if freezableObj.data == nil {
47 | return ""
48 | }
49 | return *freezableObj.data
50 | }
51 |
52 | // String ...
53 | func (freezableObj String) String() string {
54 | return freezableObj.Get()
55 | }
56 |
57 | // --- StringSlice ----------------------------
58 |
59 | // StringSlice ...
60 | type StringSlice struct {
61 | data *[]string
62 | isFrozen bool
63 | }
64 |
65 | // Set ...
66 | func (freezableObj *StringSlice) Set(s []string) error {
67 | if freezableObj.isFrozen {
68 | return fmt.Errorf("freezable.StringSlice: Object is already frozen. (Current value: %s) (New value was: %s)",
69 | freezableObj.Get(), s)
70 | }
71 |
72 | freezableObj.data = &s
73 | return nil
74 | }
75 |
76 | // Freeze ...
77 | func (freezableObj *StringSlice) Freeze() {
78 | freezableObj.isFrozen = true
79 | }
80 |
81 | // IsFrozen ...
82 | func (freezableObj *StringSlice) IsFrozen() bool {
83 | return freezableObj.isFrozen
84 | }
85 |
86 | // Get ...
87 | func (freezableObj StringSlice) Get() []string {
88 | if freezableObj.data == nil {
89 | return []string{}
90 | }
91 | return *freezableObj.data
92 | }
93 |
94 | // String ...
95 | func (freezableObj StringSlice) String() string {
96 | return fmt.Sprintf("%s", freezableObj.Get())
97 | }
98 |
--------------------------------------------------------------------------------
/kubectrlutils/util_test.go:
--------------------------------------------------------------------------------
1 | package kubeutils
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/ginkgo/extensions/table"
6 | . "github.com/onsi/gomega"
7 | )
8 |
9 | var _ = Describe("sanitize name", func() {
10 |
11 | DescribeTable("sanitize short names", func(in, out string) {
12 | Expect(SanitizeNameV2(in)).To(Equal(out))
13 | },
14 | Entry("basic a", "abc", "abc"),
15 | Entry("basic b", "abc123", "abc123"),
16 | Entry("subX *", "bb*", "bb-"),
17 | Entry("sub *", "bb*b", "bb-b"),
18 | Entry("subX /", "bb/", "bb-"),
19 | Entry("sub /", "bb/b", "bb-b"),
20 | Entry("subX .", "bb.", "bb-"),
21 | Entry("sub .", "bb.b", "bb-b"),
22 | Entry("sub0 [", "bb[", "bb"),
23 | Entry("sub [", "bb[b", "bbb"),
24 | Entry("sub0 ]", "bb]", "bb"),
25 | Entry("sub ]", "bb]b", "bbb"),
26 | Entry("subX :", "bb:", "bb-"),
27 | Entry("sub :", "bb:b", "bb-b"),
28 | Entry("subX space", "bb ", "bb-"),
29 | Entry("sub space", "bb b", "bb-b"),
30 | Entry("subX newline", "bb\n", "bb"),
31 | Entry("sub newline", "bb\nb", "bbb"),
32 | Entry("sub0 quote", "aa\"", "aa"),
33 | Entry("sub quote b", "bb\"b", "bbb"),
34 | Entry("sub0 single quote", "aa'", "aa"),
35 | Entry("sub single quote b", "bb'b", "bbb"),
36 | // these are technically invalid kube names, as are the subX cases, but user should know that and kube wil warn
37 | Entry("invalid a", "123", "123"),
38 | Entry("invalid b", "-abc", "-abc"),
39 | )
40 |
41 | DescribeTable("sanitize long names", func(in, out string) {
42 | sanitized := SanitizeNameV2(in)
43 | Expect(sanitized).To(Equal(out))
44 | Expect(len(sanitized)).To(BeNumerically("<=", 63))
45 | },
46 | Entry("300a's", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
47 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-4e5475d125a33c6190718e75adc1b70"),
48 | Entry("301a's", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
49 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-c73301b7b71679067b02cff4cdc5e70"),
50 | )
51 | })
52 |
--------------------------------------------------------------------------------
/surveyutils/input_test.go:
--------------------------------------------------------------------------------
1 | package surveyutils_test
2 |
3 | import (
4 | . "github.com/onsi/ginkgo"
5 | . "github.com/onsi/gomega"
6 | "github.com/wx-chevalier/go-utils/surveyutils"
7 | clitestutils "github.com/wx-chevalier/go-utils/testutils/cli"
8 | )
9 |
10 | var _ = Describe("GetInput", func() {
11 | Context("bool input", func() {
12 | It("correctly sets the input value", func() {
13 | clitestutils.ExpectInteractive(func(c *clitestutils.Console) {
14 | c.ExpectString("test msg [y/N]: ")
15 | c.SendLine("y")
16 | c.ExpectEOF()
17 | }, func() {
18 | var val bool
19 | err := surveyutils.GetBoolInput("test msg", &val)
20 | Expect(err).NotTo(HaveOccurred())
21 | Expect(val).To(BeTrue())
22 | })
23 | })
24 | })
25 |
26 | Context("list select", func() {
27 | var options = []string{"one", "two", "three"}
28 | Context("single select", func() {
29 | It("can select 1 from list", func() {
30 | clitestutils.ExpectInteractive(func(c *clitestutils.Console) {
31 | c.ExpectString("select option")
32 | c.PressDown()
33 | c.SendLine("")
34 | c.ExpectEOF()
35 | }, func() {
36 | var val string
37 | err := surveyutils.ChooseFromList("select option", &val, options)
38 | Expect(err).NotTo(HaveOccurred())
39 | Expect(val).To(Equal("two"))
40 | })
41 | })
42 | })
43 | Context("multi select", func() {
44 | It("can select one from a mutli-select list", func() {
45 | clitestutils.ExpectInteractive(func(c *clitestutils.Console) {
46 | c.ExpectString("select option")
47 | c.PressDown()
48 | c.Send(" ")
49 | c.SendLine("")
50 | c.ExpectEOF()
51 | }, func() {
52 | var val []string
53 | err := surveyutils.ChooseMultiFromList("select option", &val, options)
54 | Expect(err).NotTo(HaveOccurred())
55 | Expect(val).To(Equal([]string{"two"}))
56 | })
57 | })
58 |
59 | It("can select mutli from a mutli-select list", func() {
60 | clitestutils.ExpectInteractive(func(c *clitestutils.Console) {
61 | c.ExpectString("select option")
62 | c.PressDown()
63 | c.Send(" ")
64 | c.PressDown()
65 | c.Send(" ")
66 | c.SendLine("")
67 | c.ExpectEOF()
68 | }, func() {
69 | var val []string
70 | err := surveyutils.ChooseMultiFromList("select option", &val, options)
71 | Expect(err).NotTo(HaveOccurred())
72 | Expect(val).To(Equal([]string{"two", "three"}))
73 | })
74 | })
75 | })
76 | })
77 | })
78 |
--------------------------------------------------------------------------------
/configutils/config_map_client.go:
--------------------------------------------------------------------------------
1 | package configutils
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/wx-chevalier/go-utils/contextutils"
7 | "go.uber.org/zap"
8 | v1 "k8s.io/api/core/v1"
9 | kubeerr "k8s.io/apimachinery/pkg/api/errors"
10 | kubemeta "k8s.io/apimachinery/pkg/apis/meta/v1"
11 | "k8s.io/client-go/kubernetes"
12 | )
13 |
14 | type ConfigMapClient interface {
15 | GetConfigMap(ctx context.Context, namespace string, name string) (*v1.ConfigMap, error)
16 | SetConfigMap(ctx context.Context, config *v1.ConfigMap) error
17 | }
18 |
19 | type KubeConfigMapClient struct {
20 | client kubernetes.Interface
21 | }
22 |
23 | func NewConfigMapClient(client kubernetes.Interface) ConfigMapClient {
24 | return &KubeConfigMapClient{
25 | client: client,
26 | }
27 | }
28 |
29 | func (c *KubeConfigMapClient) GetConfigMap(ctx context.Context, namespace string, configMapName string) (*v1.ConfigMap, error) {
30 | contextutils.LoggerFrom(ctx).Debugw("Getting config map from Kubernetes",
31 | zap.String("namespace", namespace),
32 | zap.String("name", configMapName))
33 | configMap, err := c.client.CoreV1().ConfigMaps(namespace).Get(configMapName, kubemeta.GetOptions{})
34 | if err != nil {
35 | contextutils.LoggerFrom(ctx).Errorw("Could not get config map",
36 | zap.Error(err),
37 | zap.String("name", configMapName),
38 | zap.String("namespace", namespace))
39 | return nil, err
40 | }
41 | return configMap, nil
42 | }
43 |
44 | func (c *KubeConfigMapClient) SetConfigMap(ctx context.Context, config *v1.ConfigMap) error {
45 | contextutils.LoggerFrom(ctx).Debugw("Setting config map in Kubernetes",
46 | zap.String("namespace", config.Namespace),
47 | zap.String("name", config.Name))
48 | _, err := c.client.CoreV1().ConfigMaps(config.Namespace).Update(config)
49 | if err != nil {
50 | if !kubeerr.IsNotFound(err) {
51 | contextutils.LoggerFrom(ctx).Errorw("Could not update config map",
52 | zap.Error(err),
53 | zap.String("name", config.Name),
54 | zap.String("namespace", config.Namespace),
55 | zap.Any("configMap", config))
56 | return err
57 | }
58 | _, err := c.client.CoreV1().ConfigMaps(config.Namespace).Create(config)
59 | if err != nil {
60 | contextutils.LoggerFrom(ctx).Errorw("Config map not found, but error creating it",
61 | zap.Error(err),
62 | zap.String("name", config.Name),
63 | zap.String("namespace", config.Namespace),
64 | zap.Any("configMap", config))
65 | return err
66 | }
67 | }
68 | return nil
69 | }
70 |
--------------------------------------------------------------------------------
/fileutils/writter.go:
--------------------------------------------------------------------------------
1 | package fileutils
2 |
3 | import (
4 | "errors"
5 | "log"
6 | "os"
7 | )
8 |
9 | // WriteStringToFile ...
10 | func WriteStringToFile(pth string, fileCont string) error {
11 | return WriteBytesToFile(pth, []byte(fileCont))
12 | }
13 |
14 | // WriteStringToFileWithPermission ...
15 | func WriteStringToFileWithPermission(pth string, fileCont string, perm os.FileMode) error {
16 | return WriteBytesToFileWithPermission(pth, []byte(fileCont), perm)
17 | }
18 |
19 | // WriteBytesToFileWithPermission ...
20 | func WriteBytesToFileWithPermission(pth string, fileCont []byte, perm os.FileMode) error {
21 | if pth == "" {
22 | return errors.New("No path provided")
23 | }
24 |
25 | var file *os.File
26 | var err error
27 | if perm == 0 {
28 | file, err = os.Create(pth)
29 | } else {
30 | // same as os.Create, but with a specified permission
31 | // the flags are copy-pasted from the official
32 | // os.Create func: https://golang.org/src/os/file.go?s=7327:7366#L244
33 | file, err = os.OpenFile(pth, os.O_RDWR|os.O_CREATE|os.O_TRUNC, perm)
34 | }
35 | if err != nil {
36 | return err
37 | }
38 | defer func() {
39 | if err := file.Close(); err != nil {
40 | log.Println(" [!] Failed to close file:", err)
41 | }
42 | }()
43 |
44 | if _, err := file.Write(fileCont); err != nil {
45 | return err
46 | }
47 |
48 | return nil
49 | }
50 |
51 | // WriteBytesToFile ...
52 | func WriteBytesToFile(pth string, fileCont []byte) error {
53 | return WriteBytesToFileWithPermission(pth, fileCont, 0)
54 | }
55 |
56 | // AppendStringToFile ...
57 | func AppendStringToFile(pth string, fileCont string) error {
58 | return AppendBytesToFile(pth, []byte(fileCont))
59 | }
60 |
61 | // AppendBytesToFile ...
62 | func AppendBytesToFile(pth string, fileCont []byte) error {
63 | if pth == "" {
64 | return errors.New("No path provided")
65 | }
66 |
67 | var file *os.File
68 | filePerm, err := GetFilePermissions(pth)
69 | if err != nil {
70 | // create the file
71 | file, err = os.Create(pth)
72 | } else {
73 | // open for append
74 | file, err = os.OpenFile(pth, os.O_APPEND|os.O_CREATE|os.O_WRONLY, filePerm)
75 | }
76 | if err != nil {
77 | // failed to create or open-for-append the file
78 | return err
79 | }
80 | defer func() {
81 | if err := file.Close(); err != nil {
82 | log.Println(" [!] Failed to close file:", err)
83 | }
84 | }()
85 |
86 | if _, err := file.Write(fileCont); err != nil {
87 | return err
88 | }
89 |
90 | return nil
91 | }
92 |
--------------------------------------------------------------------------------
/fileutils/tar_test.go:
--------------------------------------------------------------------------------
1 | package fileutils
2 |
3 | import (
4 | "path/filepath"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | "github.com/spf13/afero"
9 | )
10 |
11 | var _ = Describe("tarutils", func() {
12 | Context("File system", func() {
13 | It("can tar/untar files", func() {
14 | fs := afero.NewOsFs()
15 | tmpDir := mustWriteTestDir(fs)
16 | mustAddTestFiles(tmpDir, fs)
17 | tmp, err := afero.TempFile(fs, "", "tar-zipped-file-")
18 | Expect(err).NotTo(HaveOccurred())
19 | err = Tar(tmpDir, fs, tmp)
20 | Expect(err).NotTo(HaveOccurred())
21 |
22 | newTmpDir := mustWriteTestDir(fs)
23 | err = Untar(newTmpDir, tmp.Name(), fs)
24 | Expect(err).NotTo(HaveOccurred())
25 |
26 | mustFindOriginalFiles(newTmpDir, fs)
27 | })
28 | })
29 |
30 | Context("Mem map", func() {
31 | It("can tar/untar files", func() {
32 | fs := afero.NewMemMapFs()
33 | tmpDir := mustWriteTestDir(fs)
34 | mustAddTestFiles(tmpDir, fs)
35 | tmp, err := afero.TempFile(fs, "", "tar-zipped-file-")
36 | Expect(err).NotTo(HaveOccurred())
37 | err = Tar(tmpDir, fs, tmp)
38 | Expect(err).NotTo(HaveOccurred())
39 |
40 | newTmpDir := mustWriteTestDir(fs)
41 | err = Untar(newTmpDir, tmp.Name(), fs)
42 | Expect(err).NotTo(HaveOccurred())
43 |
44 | mustFindOriginalFiles(newTmpDir, fs)
45 | })
46 | })
47 | })
48 |
49 | func mustFindOriginalFiles(newTmpDir string, fs afero.Fs) {
50 | files, err := afero.ReadDir(fs, newTmpDir)
51 | Expect(err).NotTo(HaveOccurred())
52 | for _, v := range files {
53 | if !v.IsDir() {
54 | _, err := afero.ReadFile(fs, newTmpDir+"/"+v.Name())
55 | Expect(err).NotTo(HaveOccurred())
56 | } else {
57 | mustFindOriginalFiles(filepath.Join(newTmpDir, v.Name()), fs)
58 | }
59 | }
60 | }
61 |
62 | func mustWriteTestDir(fs afero.Fs) string {
63 | tmpDir, err := afero.TempDir(fs, "", "tar-test-")
64 | Expect(err).NotTo(HaveOccurred())
65 | return tmpDir
66 | }
67 |
68 | func mustAddTestFiles(tmpdir string, fs afero.Fs) {
69 | dir, err := afero.TempDir(fs, tmpdir, "tar-test-nested-folder")
70 | Expect(err).NotTo(HaveOccurred())
71 | file, err := afero.TempFile(fs, tmpdir, "tar-test-file-")
72 | Expect(err).NotTo(HaveOccurred())
73 | err = afero.WriteFile(fs, file.Name(), []byte("first file"), 0777)
74 | Expect(err).NotTo(HaveOccurred())
75 | file, err = afero.TempFile(fs, dir, "tar-test-file-")
76 | Expect(err).NotTo(HaveOccurred())
77 | err = afero.WriteFile(fs, file.Name(), []byte("second file"), 0777)
78 | Expect(err).NotTo(HaveOccurred())
79 | }
80 |
--------------------------------------------------------------------------------
/botutils/server.go:
--------------------------------------------------------------------------------
1 | package botutils
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/wx-chevalier/go-utils/botutils/botconfig"
10 |
11 | "github.com/palantir/go-baseapp/baseapp"
12 | "github.com/palantir/go-githubapp/githubapp"
13 | "github.com/rs/zerolog"
14 | "github.com/wx-chevalier/go-utils/contextutils"
15 | "goji.io/pat"
16 | )
17 |
18 | type StaticBotConfig struct {
19 | BotName string
20 | Version string
21 | }
22 |
23 | type GitBot interface {
24 | Start(ctx context.Context, plugins ...Plugin) error
25 | }
26 |
27 | // This bot doesn't read any configuration from the repo, just uses the application config and static config provided
28 | type simpleGitBot struct {
29 | staticConfig StaticBotConfig
30 | config *botconfig.Config
31 | }
32 |
33 | func NewSimpleGitBot(staticConfig StaticBotConfig) (GitBot, error) {
34 | config, err := botconfig.ReadConfig()
35 | if err != nil {
36 | return nil, err
37 | }
38 | return &simpleGitBot{
39 | config: config,
40 | staticConfig: staticConfig,
41 | }, nil
42 | }
43 |
44 | func (b *simpleGitBot) Start(ctx context.Context, plugins ...Plugin) error {
45 | cc, err := githubapp.NewDefaultCachingClientCreator(
46 | b.config.Github,
47 | githubapp.WithClientUserAgent(fmt.Sprintf("%s/%s", b.staticConfig.BotName, b.staticConfig.Version)),
48 | githubapp.WithClientMiddleware(
49 | githubapp.ClientLogging(zerolog.DebugLevel),
50 | ),
51 | )
52 | if err != nil {
53 | return err
54 | }
55 |
56 | contextutils.LoggerFrom(ctx).Infow(fmt.Sprintf("Hello from %s!", b.staticConfig.BotName))
57 | // baseapp library requires zerolog, we use zap everywhere else :(
58 | logger := zerolog.Ctx(ctx)
59 | if logger == nil {
60 | tmp := zerolog.New(os.Stdout).With().Timestamp().Logger()
61 | logger = &tmp
62 | }
63 | server, err := baseapp.NewServer(
64 | b.config.Server,
65 | baseapp.DefaultParams(*logger, fmt.Sprintf("%s.", b.staticConfig.BotName))...,
66 | )
67 | if err != nil {
68 | return err
69 | }
70 |
71 | githubHandler := NewGithubHookHandler(ctx, cc)
72 | for _, p := range plugins {
73 | githubHandler.RegisterPlugin(p)
74 | }
75 | webhookHandler := githubapp.NewDefaultEventDispatcher(b.config.Github, githubHandler)
76 | server.Mux().Handle(pat.Post(githubapp.DefaultWebhookRoute), webhookHandler)
77 | server.Mux().Handle(pat.New("/"), _200ok())
78 |
79 | // Start is blocking
80 | return server.Start()
81 | }
82 |
83 | func _200ok() http.Handler {
84 | return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
85 | }
86 |
--------------------------------------------------------------------------------
/kubeinstallutils/kubeinstall/installer_callbacks.go:
--------------------------------------------------------------------------------
1 | package kubeinstall
2 |
3 | import (
4 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
5 | )
6 |
7 | type CallbackOptions interface {
8 | PreInstall() error
9 | PostInstall() error
10 | PreCreate(res *unstructured.Unstructured) error
11 | PostCreate(res *unstructured.Unstructured) error
12 | PreUpdate(res *unstructured.Unstructured) error
13 | PostUpdate(res *unstructured.Unstructured) error
14 | PreDelete(res *unstructured.Unstructured) error
15 | PostDelete(res *unstructured.Unstructured) error
16 | }
17 |
18 | type CallbackOption struct {
19 | OnPreInstall func() error
20 | OnPostInstall func() error
21 | OnPreCreate func(res *unstructured.Unstructured) error
22 | OnPostCreate func(res *unstructured.Unstructured) error
23 | OnPreUpdate func(res *unstructured.Unstructured) error
24 | OnPostUpdate func(res *unstructured.Unstructured) error
25 | OnPreDelete func(res *unstructured.Unstructured) error
26 | OnPostDelete func(res *unstructured.Unstructured) error
27 | }
28 |
29 | func (cb *CallbackOption) PreInstall() error {
30 | if cb.OnPreInstall != nil {
31 | return cb.OnPreInstall()
32 | }
33 | return nil
34 | }
35 |
36 | func (cb *CallbackOption) PostInstall() error {
37 | if cb.OnPostInstall != nil {
38 | return cb.OnPostInstall()
39 | }
40 | return nil
41 | }
42 |
43 | func (cb *CallbackOption) PreCreate(res *unstructured.Unstructured) error {
44 | if cb.OnPreCreate != nil {
45 | return cb.OnPreCreate(res)
46 | }
47 | return nil
48 | }
49 |
50 | func (cb *CallbackOption) PostCreate(res *unstructured.Unstructured) error {
51 | if cb.OnPostCreate != nil {
52 | return cb.OnPostCreate(res)
53 | }
54 | return nil
55 | }
56 |
57 | func (cb *CallbackOption) PreUpdate(res *unstructured.Unstructured) error {
58 | if cb.OnPreUpdate != nil {
59 | return cb.OnPreUpdate(res)
60 | }
61 | return nil
62 | }
63 |
64 | func (cb *CallbackOption) PostUpdate(res *unstructured.Unstructured) error {
65 | if cb.OnPostUpdate != nil {
66 | return cb.OnPostUpdate(res)
67 | }
68 | return nil
69 | }
70 |
71 | func (cb *CallbackOption) PreDelete(res *unstructured.Unstructured) error {
72 | if cb.OnPreDelete != nil {
73 | return cb.OnPreDelete(res)
74 | }
75 | return nil
76 | }
77 |
78 | func (cb *CallbackOption) PostDelete(res *unstructured.Unstructured) error {
79 | if cb.OnPostDelete != nil {
80 | return cb.OnPostDelete(res)
81 | }
82 | return nil
83 | }
84 |
85 | func initCallbacks() []CallbackOptions {
86 | return []CallbackOptions{
87 | &CallbackOption{OnPreCreate: setInstallationAnnotation},
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/kubesetuputils/install_kube_manifest_test.go:
--------------------------------------------------------------------------------
1 | package kubeinstallutils_test
2 |
3 | import (
4 | "os"
5 |
6 | . "github.com/onsi/ginkgo"
7 | . "github.com/onsi/gomega"
8 | "github.com/wx-chevalier/go-utils/kubeinstallutils"
9 | "github.com/wx-chevalier/go-utils/kubeutils"
10 | "github.com/wx-chevalier/go-utils/testutils"
11 | "github.com/wx-chevalier/go-utils/testutils/kube"
12 | "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
13 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14 | "k8s.io/client-go/kubernetes"
15 | _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
16 | )
17 |
18 | var _ = Describe("InstallKubeManifest", func() {
19 | var (
20 | namespace string
21 | kubeClient kubernetes.Interface
22 | )
23 | BeforeEach(func() {
24 | if os.Getenv("RUN_KUBE_TESTS") != "1" {
25 | Skip("use RUN_KUBE_TESTS to run this test")
26 | }
27 | namespace = "install-kube-manifest-" + testutils.RandString(8)
28 | kubeClient = kube.MustKubeClient()
29 | err := kubeutils.CreateNamespacesInParallel(kubeClient, namespace)
30 | Expect(err).NotTo(HaveOccurred())
31 | })
32 | AfterEach(func() {
33 | if kubeClient != nil {
34 | err := kubeutils.DeleteNamespacesInParallelBlocking(kubeClient, namespace)
35 | Expect(err).NotTo(HaveOccurred())
36 | }
37 | })
38 | It("installs arbitrary kube manifests", func() {
39 | err := deployNginx(namespace)
40 | Expect(err).NotTo(HaveOccurred())
41 |
42 | cfg, err := kubeutils.GetConfig("", "")
43 | Expect(err).NotTo(HaveOccurred())
44 | kube, err := kubernetes.NewForConfig(cfg)
45 | Expect(err).NotTo(HaveOccurred())
46 |
47 | svcs, err := kube.CoreV1().Services(namespace).List(v1.ListOptions{})
48 | Expect(err).NotTo(HaveOccurred())
49 | deployments, err := kube.ExtensionsV1beta1().Deployments(namespace).List(v1.ListOptions{})
50 | Expect(err).NotTo(HaveOccurred())
51 | Expect(svcs.Items).To(HaveLen(1))
52 | Expect(deployments.Items).To(HaveLen(1))
53 |
54 | })
55 | })
56 |
57 | func deployNginx(namespace string) error {
58 | cfg, err := kubeutils.GetConfig("", "")
59 | if err != nil {
60 | return err
61 | }
62 | kube, err := kubernetes.NewForConfig(cfg)
63 | if err != nil {
64 | return err
65 | }
66 |
67 | apiext, err := clientset.NewForConfig(cfg)
68 | if err != nil {
69 | return err
70 | }
71 |
72 | installer := kubeinstallutils.NewKubeInstaller(kube, apiext, namespace)
73 |
74 | kubeObjs, err := kubeinstallutils.ParseKubeManifest(testutils.NginxYaml)
75 | if err != nil {
76 | return err
77 | }
78 |
79 | for _, kubeOjb := range kubeObjs {
80 | if err := installer.Create(kubeOjb); err != nil {
81 | return err
82 | }
83 | }
84 | return nil
85 | }
86 |
--------------------------------------------------------------------------------
/testutils/trimmed_stack_fail_handler.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "fmt"
7 | "os"
8 | "regexp"
9 | "runtime/debug"
10 | )
11 |
12 | //PrintTrimmedStack helps you find the line of the failing assertion without producing excessive noise.
13 | // This is achieved by printing a stack trace and pruning lines associated with known overhead.
14 | // With this fail handler, you do not need to count stack offsets ExpectWithOffset(x, ...) and can just Expect(...)
15 | func PrintTrimmedStack() {
16 | stack := debug.Stack()
17 | fmt.Println(trimVendorStack(stack))
18 | }
19 | func trimVendorStack(stack []byte) string {
20 | scanner := bufio.NewScanner(bytes.NewReader(stack))
21 | ind := -1
22 | pair := []string{}
23 | skipCount := 0
24 | output := ""
25 | for scanner.Scan() {
26 | ind++
27 | if ind == 0 {
28 | // skip the header
29 | continue
30 | }
31 | pair = append(pair, scanner.Text())
32 | if len(pair) == 2 {
33 | evaluateStackPair(pair[0], pair[1], &output, &skipCount)
34 | pair = []string{}
35 | }
36 | }
37 | if err := scanner.Err(); err != nil {
38 | fmt.Fprintln(os.Stderr, "reading standard input:", err)
39 | }
40 | output = fmt.Sprintf("Stack trace (skipped %v entries that matched filter criteria):\n%v", skipCount, output)
41 | return output
42 | }
43 |
44 | var (
45 | funcRuntimeDebugRegex = ®exp.Regexp{}
46 | fileVendorRegex = ®exp.Regexp{}
47 | fileGoModRegex = ®exp.Regexp{}
48 | fileSuiteRegex = ®exp.Regexp{}
49 | fileGoTestLibRegex = ®exp.Regexp{}
50 | fileSelfDescription = ®exp.Regexp{}
51 | )
52 |
53 | func init() {
54 | funcRuntimeDebugRegex = regexp.MustCompile("runtime/debug")
55 | fileVendorRegex = regexp.MustCompile("vendor")
56 | fileGoModRegex = regexp.MustCompile("/go/pkg/mod/")
57 | fileSuiteRegex = regexp.MustCompile("suite_test.go")
58 | fileGoTestLibRegex = regexp.MustCompile("src/testing/testing.go")
59 | fileSelfDescription = regexp.MustCompile("wx-chevalier/go-utils/testutils/trimmed")
60 | }
61 |
62 | func evaluateStackPair(functionLine, fileLine string, output *string, skipCount *int) {
63 | skip := false
64 | if funcRuntimeDebugRegex.MatchString(functionLine) {
65 | skip = true
66 | }
67 | if fileVendorRegex.MatchString(fileLine) ||
68 | fileGoModRegex.MatchString(fileLine) ||
69 | fileSuiteRegex.MatchString(fileLine) ||
70 | fileGoTestLibRegex.MatchString(fileLine) ||
71 | fileSelfDescription.MatchString(fileLine) {
72 | skip = true
73 | }
74 | if skip {
75 | *skipCount = *skipCount + 1
76 | return
77 | }
78 | *output = fmt.Sprintf("%v%v\n%v\n", *output, functionLine, fileLine)
79 | return
80 | }
81 |
--------------------------------------------------------------------------------