├── .gitignore ├── f5teem ├── go.mod ├── go.sum ├── config.go ├── f5teem_test.go ├── README.md ├── f5teem.go └── LICENSE ├── CHANGELOG.md ├── vendor ├── github.com │ ├── stretchr │ │ └── testify │ │ │ ├── require │ │ │ ├── require_forward.go.tmpl │ │ │ ├── require.go.tmpl │ │ │ ├── requirements.go │ │ │ ├── forward_requirements.go │ │ │ └── doc.go │ │ │ ├── assert │ │ │ ├── assertion_format.go.tmpl │ │ │ ├── assertion_forward.go.tmpl │ │ │ ├── errors.go │ │ │ ├── forward_assertions.go │ │ │ ├── doc.go │ │ │ └── http_assertions.go │ │ │ ├── LICENSE │ │ │ └── suite │ │ │ ├── interfaces.go │ │ │ ├── doc.go │ │ │ └── suite.go │ ├── davecgh │ │ └── go-spew │ │ │ ├── LICENSE │ │ │ └── spew │ │ │ ├── bypasssafe.go │ │ │ ├── bypass.go │ │ │ ├── spew.go │ │ │ ├── doc.go │ │ │ ├── common.go │ │ │ ├── format.go │ │ │ ├── config.go │ │ │ └── dump.go │ └── pmezard │ │ └── go-difflib │ │ └── LICENSE └── modules.txt ├── .travis.yml ├── go.mod ├── go.sum ├── examples ├── access │ ├── main.go │ ├── test_access_profile.go │ └── test_access_policy.go ├── asm │ ├── main.go │ └── test_asm.go ├── ltm │ └── main.go └── go-bigip_example.go ├── Gopkg.toml ├── Gopkg.lock ├── LICENSE ├── partitions.go ├── cmd └── webtop_example │ └── example.go ├── shared.go ├── README.md ├── vcmp.go ├── application.go ├── utility.go ├── app.go ├── gtm.go ├── device.go └── apm.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | *.back 4 | *.swp 5 | -------------------------------------------------------------------------------- /f5teem/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/f5devcentral/go-bigip/f5teem 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/google/uuid v1.1.1 7 | github.com/satori/go.uuid v1.2.0 // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.1 (Unreleased) 2 | 3 | ## 0.1.0 4 | - Added app.go 5 | - Added vxlan in net.go 6 | - Added net_test.go 7 | - Updated device.go 8 | - Added device_test.go 9 | 10 | 11 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { 3 | {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 4 | } 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | matrix: 4 | include: 5 | - go: 1.8 6 | - go: 1.9 7 | - go: tip 8 | allow_failures: 9 | - go: tip 10 | 11 | env: 12 | - TEEM_API_ENVIRONMENT=staging 13 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentFormat}} 2 | func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { 3 | return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) 4 | } 5 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 4 | } 5 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.Comment}} 2 | func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { 3 | if !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { 4 | t.FailNow() 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/f5devcentral/go-bigip 2 | 3 | go 1.20 4 | 5 | require github.com/stretchr/testify v1.2.1 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.0 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /f5teem/go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 2 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 3 | github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= 4 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 5 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // TestingT is an interface wrapper around *testing.T 4 | type TestingT interface { 5 | Errorf(format string, args ...interface{}) 6 | FailNow() 7 | } 8 | 9 | //go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs 10 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/davecgh/go-spew v1.1.0 2 | ## explicit 3 | github.com/davecgh/go-spew/spew 4 | # github.com/pmezard/go-difflib v1.0.0 5 | ## explicit 6 | github.com/pmezard/go-difflib/difflib 7 | # github.com/stretchr/testify v1.2.1 8 | ## explicit 9 | github.com/stretchr/testify/assert 10 | github.com/stretchr/testify/require 11 | github.com/stretchr/testify/suite 12 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/forward_requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs 17 | -------------------------------------------------------------------------------- /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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U= 6 | github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 7 | -------------------------------------------------------------------------------- /examples/access/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/f5devcentral/go-bigip" 5 | ) 6 | 7 | func main() { 8 | // Connect to the BIG-IP system. 9 | // Replace with your actual BIG-IP credentials and hostname 10 | config := &bigip.Config{ 11 | Address: "https://192.168.1.1", 12 | Username: "admin", 13 | Password: "admin", 14 | CertVerifyDisable: true, // Disable certificate verification for testing purposes 15 | } 16 | f5 := bigip.NewSession(config) 17 | testAccessPolicy(f5) 18 | testAccessProfiles(f5) 19 | } 20 | -------------------------------------------------------------------------------- /examples/asm/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/f5devcentral/go-bigip" 5 | ) 6 | 7 | func main() { 8 | // Connect to the BIG-IP system. 9 | // Replace with your actual BIG-IP credentials and hostname 10 | config := &bigip.Config{ 11 | Address: "https://192.168.1.1", 12 | Username: "admin", 13 | Password: "admin", 14 | CertVerifyDisable: true, // Disable certificate verification for testing purposes 15 | } 16 | f5 := bigip.NewSession(config) 17 | testDosProfile(f5) 18 | testFirewallPolicy(f5) 19 | testIpIntelligence(f5) 20 | testLogProfile(f5) 21 | } 22 | -------------------------------------------------------------------------------- /examples/ltm/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/f5devcentral/go-bigip" 5 | ) 6 | 7 | func main() { 8 | // Connect to the BIG-IP system. 9 | // Replace with your actual BIG-IP credentials and hostname 10 | config := &bigip.Config{ 11 | Address: "https://192.168.1.1", 12 | Username: "admin", 13 | Password: "admin", 14 | CertVerifyDisable: true, // Disable certificate verification for testing purposes 15 | } 16 | f5 := bigip.NewSession(config) 17 | testUDPProfile(f5) 18 | testWebsocketProfile(f5) 19 | testHTMLProfile(f5) 20 | testAnalyticsProfile(f5) 21 | testRequestAdaptProfile(f5) 22 | testResponseAdaptProfile(f5) 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2016 Dave Collins 4 | 5 | Permission to use, copy, modify, and distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [[constraint]] 29 | name = "github.com/stretchr/testify" 30 | version = "1.2.1" 31 | 32 | [prune] 33 | go-tests = true 34 | unused-packages = true 35 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | name = "github.com/davecgh/go-spew" 6 | packages = ["spew"] 7 | revision = "346938d642f2ec3594ed81d874461961cd0faa76" 8 | version = "v1.1.0" 9 | 10 | [[projects]] 11 | name = "github.com/pmezard/go-difflib" 12 | packages = ["difflib"] 13 | revision = "792786c7400a136282c1664665ae0a8db921c6c2" 14 | version = "v1.0.0" 15 | 16 | [[projects]] 17 | name = "github.com/stretchr/testify" 18 | packages = [ 19 | "assert", 20 | "require", 21 | "suite" 22 | ] 23 | revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" 24 | version = "v1.2.1" 25 | 26 | [solve-meta] 27 | analyzer-name = "dep" 28 | analyzer-version = 1 29 | inputs-digest = "1b10b1e002262a75c43af1c7f27d9a5df6b0662f1d76892ca432e3835a3cc704" 30 | solver-name = "gps-cdcl" 31 | solver-version = 1 32 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/doc.go: -------------------------------------------------------------------------------- 1 | // Package require implements the same assertions as the `assert` package but 2 | // stops test execution when a test fails. 3 | // 4 | // Example Usage 5 | // 6 | // The following is a complete example using require in a standard test function: 7 | // import ( 8 | // "testing" 9 | // "github.com/stretchr/testify/require" 10 | // ) 11 | // 12 | // func TestSomething(t *testing.T) { 13 | // 14 | // var a string = "Hello" 15 | // var b string = "Hello" 16 | // 17 | // require.Equal(t, a, b, "The two words should be the same.") 18 | // 19 | // } 20 | // 21 | // Assertions 22 | // 23 | // The `require` package have same global functions as in the `assert` package, 24 | // but instead of returning a boolean result they call `t.FailNow()`. 25 | // 26 | // Every assertion function also takes an optional string message as the final argument, 27 | // allowing custom error messages to be appended to the message the assertion method outputs. 28 | package require 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Scott Ware 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /examples/access/test_access_profile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/f5devcentral/go-bigip" 6 | "log" 7 | ) 8 | 9 | // test access-profile 10 | func testAccessProfiles(f5 *bigip.BigIP) { 11 | // Example 1: List all existing Access Profiles 12 | fmt.Println("1. Listing all existing Access Profiles...") 13 | listAccessProfiles(f5) 14 | } 15 | 16 | // listAccessProfiles demonstrates how to retrieve all access profiles 17 | func listAccessProfiles(f5 *bigip.BigIP) { 18 | profiles, err := f5.AccessProfiles() 19 | if err != nil { 20 | log.Printf("Error retrieving access profiles: %v", err) 21 | return 22 | } 23 | 24 | if len(profiles.AccessProfiles) == 0 { 25 | fmt.Println("No access profiles found.") 26 | return 27 | } 28 | 29 | fmt.Printf("Found %d access profile(s):\n", len(profiles.AccessProfiles)) 30 | for i, profile := range profiles.AccessProfiles { 31 | fmt.Printf(" %d. Name: %s, Partition: %s, Type: %s\n", 32 | i+1, profile.Name, profile.Partition, profile.Type) 33 | if profile.Description != "" { 34 | fmt.Printf(" Description: %s\n", profile.Description) 35 | } 36 | fmt.Printf(" Full Path: %s\n", profile.FullPath) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell 2 | 3 | Please consider promoting this project if you find it useful. 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of the Software, 10 | and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 21 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 22 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /f5teem/config.go: -------------------------------------------------------------------------------- 1 | package f5teem 2 | 3 | var envList = []string{"production", "staging"} 4 | var envVar = map[string]interface{}{ 5 | "published": envList, 6 | "env_var": "TEEM_API_ENVIRONMENT", 7 | } 8 | var prodEnd = map[string]string{ 9 | "endpoint": "product.apis.f5.com", 10 | "api_key": "mmhJU2sCd63BznXAXDh4kxLIyfIMm3Ar", 11 | } 12 | var stagEnd = map[string]string{ 13 | "endpoint": "product-tst.apis.f5networks.net", 14 | "api_key": "", 15 | } 16 | var k = map[string]interface{}{ 17 | "production": prodEnd, 18 | "staging": stagEnd, 19 | } 20 | var endPoints = map[string]interface{}{ 21 | "anonymous": k, 22 | } 23 | 24 | const ( 25 | productName string = "Automation Toolchain" 26 | productVersion string = "1.0.2" 27 | userAgent = "f5-teem/${version}" 28 | ) 29 | 30 | type TeemObject struct { 31 | //EndpointInfo interface{} 32 | ClientInfo AssetInfo 33 | ApiKey string 34 | TelemetryType string 35 | TelemetryTypeVersion string 36 | ServiceHost string 37 | } 38 | type clientConfig struct { 39 | ClientInfo string 40 | ApiKey string 41 | } 42 | 43 | type AssetInfo struct { 44 | Name string `json:"name,omitempty"` 45 | Version string `json:"version,omitempty"` 46 | Id string `json:"id,omitempty"` 47 | } 48 | -------------------------------------------------------------------------------- /partitions.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2019 F5 Networks Inc 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | */ 11 | package bigip 12 | 13 | // TMPartitions contains a list of all partitions on the BIG-IP system. 14 | type TMPartitions struct { 15 | TMPartitions []*TMPartition `json:"items"` 16 | } 17 | 18 | type TMPartition struct { 19 | Name string `json:"name,omitempty"` 20 | Kind string `json:"kind,omitempty"` 21 | DefaultRouteDomain int `json:"defaultRouteDomain,omitempty"` 22 | FullPath string `json:"fullPath,omitempty"` 23 | SelfLink string `json:"selfLink,omitempty"` 24 | } 25 | 26 | // TMPartitions returns a list of partitions. 27 | func (b *BigIP) TMPartitions() (*TMPartitions, error) { 28 | var pList TMPartitions 29 | if err, _ := b.getForEntity(&pList, "auth", "tmPartition"); err != nil { 30 | return nil, err 31 | } 32 | return &pList, nil 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/suite/interfaces.go: -------------------------------------------------------------------------------- 1 | package suite 2 | 3 | import "testing" 4 | 5 | // TestingSuite can store and return the current *testing.T context 6 | // generated by 'go test'. 7 | type TestingSuite interface { 8 | T() *testing.T 9 | SetT(*testing.T) 10 | } 11 | 12 | // SetupAllSuite has a SetupSuite method, which will run before the 13 | // tests in the suite are run. 14 | type SetupAllSuite interface { 15 | SetupSuite() 16 | } 17 | 18 | // SetupTestSuite has a SetupTest method, which will run before each 19 | // test in the suite. 20 | type SetupTestSuite interface { 21 | SetupTest() 22 | } 23 | 24 | // TearDownAllSuite has a TearDownSuite method, which will run after 25 | // all the tests in the suite have been run. 26 | type TearDownAllSuite interface { 27 | TearDownSuite() 28 | } 29 | 30 | // TearDownTestSuite has a TearDownTest method, which will run after 31 | // each test in the suite. 32 | type TearDownTestSuite interface { 33 | TearDownTest() 34 | } 35 | 36 | // BeforeTest has a function to be executed right before the test 37 | // starts and receives the suite and test names as input 38 | type BeforeTest interface { 39 | BeforeTest(suiteName, testName string) 40 | } 41 | 42 | // AfterTest has a function to be executed right after the test 43 | // finishes and receives the suite and test names as input 44 | type AfterTest interface { 45 | AfterTest(suiteName, testName string) 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // Example Usage 4 | // 5 | // The following is a complete example using assert in a standard test function: 6 | // import ( 7 | // "testing" 8 | // "github.com/stretchr/testify/assert" 9 | // ) 10 | // 11 | // func TestSomething(t *testing.T) { 12 | // 13 | // var a string = "Hello" 14 | // var b string = "Hello" 15 | // 16 | // assert.Equal(t, a, b, "The two words should be the same.") 17 | // 18 | // } 19 | // 20 | // if you assert many times, use the format below: 21 | // 22 | // import ( 23 | // "testing" 24 | // "github.com/stretchr/testify/assert" 25 | // ) 26 | // 27 | // func TestSomething(t *testing.T) { 28 | // assert := assert.New(t) 29 | // 30 | // var a string = "Hello" 31 | // var b string = "Hello" 32 | // 33 | // assert.Equal(a, b, "The two words should be the same.") 34 | // } 35 | // 36 | // Assertions 37 | // 38 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 39 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 40 | // testing framework. This allows the assertion funcs to write the failings and other details to 41 | // the correct place. 42 | // 43 | // Every assertion function also takes an optional string message as the final argument, 44 | // allowing custom error messages to be appended to the message the assertion method outputs. 45 | package assert 46 | -------------------------------------------------------------------------------- /cmd/webtop_example/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "os" 8 | "time" 9 | 10 | "github.com/f5devcentral/go-bigip" 11 | ) 12 | 13 | func main() { 14 | // Connect to the BIG-IP system. 15 | config := bigip.Config{ 16 | Address: os.Getenv("BIG_IP_HOST"), 17 | Username: os.Getenv("BIG_IP_USER"), 18 | Password: os.Getenv("BIG_IP_PASSWORD"), 19 | CertVerifyDisable: true, 20 | } 21 | 22 | f5 := bigip.NewSession(&config) 23 | 24 | ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 25 | defer cancel() 26 | 27 | conf := bigip.WebtopConfig{ 28 | Description: "A webtop example", 29 | Type: bigip.WebtopTypePortal, 30 | LinkType: bigip.LinkTypeUri, 31 | CustomizationType: bigip.CustomizationTypeModern, 32 | CustomizationGroup: "/Common/webtop_customization", 33 | LocationSpecific: false, 34 | MinimizeToTray: true, 35 | ShowSearch: true, 36 | WarningOnClose: false, 37 | UrlEntryField: true, 38 | ResourceSearch: false, 39 | InitialState: bigip.InitialStateCollapsed, 40 | } 41 | webtop := bigip.Webtop{ 42 | Name: "ExampleName", 43 | Partition: "Common", 44 | TMPartition: "Common", 45 | WebtopConfig: conf, 46 | } 47 | 48 | err := f5.CreateWebtop(ctx, webtop) 49 | if err != nil { 50 | log.Fatalf("Failed to create webtop: %v", err) 51 | } 52 | webtopGet, err := f5.GetWebtop(ctx, webtop.Name) 53 | if err != nil { 54 | log.Fatalf("Failed to get webtop: %v", err) 55 | } 56 | fmt.Printf("%+v\n", webtopGet) 57 | err = f5.DeleteWebtop(ctx, webtop.Name) 58 | if err != nil { 59 | log.Fatalf("Failed to delete webtop: %v", err) 60 | } 61 | log.Println("Webtop created") 62 | } 63 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /shared.go: -------------------------------------------------------------------------------- 1 | package bigip 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | const ( 11 | uriShared = "shared" 12 | uriLicensing = "licensing" 13 | uriActivation = "activation" 14 | uriRegistration = "registration" 15 | uriFileTransfer = "file-transfer" 16 | uriUploads = "uploads" 17 | activationComplete = "LICENSING_COMPLETE" 18 | activationInProgress = "LICENSING_ACTIVATION_IN_PROGRESS" 19 | activationFailed = "LICENSING_FAILED" 20 | activationNeedEula = "NEED_EULA_ACCEPT" 21 | ) 22 | 23 | // Installs the given license. 24 | func (b *BigIP) InstallLicense(licenseText string) error { 25 | r := map[string]string{"licenseText": licenseText} 26 | return b.put(r, uriShared, uriLicensing, uriRegistration) 27 | } 28 | 29 | // Revoke license. 30 | func (b *BigIP) RevokeLicense() error { 31 | //r := map[string]string{"licenseText": licenseText} 32 | return b.delete(uriShared, uriLicensing, uriRegistration) 33 | } 34 | 35 | // Upload a file 36 | func (b *BigIP) UploadFile(f *os.File) (*Upload, error) { 37 | if strings.HasSuffix(f.Name(), ".iso") { 38 | err := fmt.Errorf("File must not have .iso extension") 39 | return nil, err 40 | } 41 | info, err := f.Stat() 42 | if err != nil { 43 | return nil, err 44 | } 45 | return b.Upload(f, info.Size(), uriShared, uriFileTransfer, uriUploads, info.Name()) 46 | } 47 | 48 | // Upload a file from a byte slice 49 | func (b *BigIP) UploadBytes(data []byte, filename string) (*Upload, error) { 50 | r := bytes.NewReader(data) 51 | size := int64(len(data)) 52 | return b.Upload(r, size, uriShared, uriFileTransfer, uriUploads, filename) 53 | } 54 | 55 | // Upload a file from a byte slice 56 | func (b *BigIP) UploadAsmBytes(data []byte, filename string) (*Upload, error) { 57 | r := bytes.NewReader(data) 58 | size := int64(len(data)) 59 | return b.Upload(r, size, uriTm, uriAsm, uriFileTransfer, uriUploads, filename) 60 | } 61 | -------------------------------------------------------------------------------- /f5teem/f5teem_test.go: -------------------------------------------------------------------------------- 1 | package f5teem 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | func TestTeemTelemetryRequest(t *testing.T) { 9 | assetInfo := AssetInfo{ 10 | "Terraform-Provider-BIGIP-Ecosystem", 11 | "1.2.0", 12 | "", 13 | } 14 | apiKey := os.Getenv("TEEM_API_KEY") 15 | teemDevice := AnonymousClient(assetInfo, apiKey) 16 | d := map[string]interface{}{ 17 | "Device": 1, 18 | "Tenant": 1, 19 | "License": 1, 20 | "DNS": 1, 21 | "NTP": 1, 22 | "Provision": 1, 23 | "VLAN": 2, 24 | "SelfIp": 2, 25 | "platform": "BIG-IP", 26 | "platformVersion": "15.1.0.5", 27 | } 28 | err := teemDevice.Report(d, "Terraform BIGIP-ravinder-latest", "1") 29 | if apiKey == "" && err == nil { 30 | t.Errorf("Error:%v", err) 31 | } 32 | if apiKey != "" && err != nil { 33 | t.Errorf("Error:%v", err) 34 | } 35 | } 36 | 37 | func TestTeemNotAuthorized(t *testing.T) { 38 | assetInfo := AssetInfo{ 39 | "Terraform-Provider-BIGIP-Ecosystem", 40 | "1.2.0", 41 | "", 42 | } 43 | teemDevice := AnonymousClient(assetInfo, "xxxx") 44 | d := map[string]interface{}{ 45 | "Device": 1, 46 | "Tenant": 1, 47 | "License": 1, 48 | "DNS": 1, 49 | "NTP": 1, 50 | "Provision": 1, 51 | "VLAN": 2, 52 | "SelfIp": 2, 53 | "platform": "BIG-IP", 54 | "platformVersion": "15.1.0.5", 55 | } 56 | err := teemDevice.Report(d, "Terraform BIGIP-ravinder-latest", "1") 57 | if err == nil { 58 | t.Errorf("Error:%v", err) 59 | } 60 | } 61 | 62 | func TestUniqueUUID(t *testing.T) { 63 | expected := "a837ce9d-d34c-e5c1-9fe0-581e2b46c029" 64 | oldOS := osHostname 65 | defer func() { osHostname = oldOS }() 66 | 67 | osHostname = func() (hostname string, err error) { 68 | return "foobar.local.lab", nil 69 | } 70 | result := uniqueUUID() 71 | if result != expected { 72 | t.Errorf("Expected UUID to be: %s, got %s", expected, result) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /f5teem/README.md: -------------------------------------------------------------------------------- 1 | # f5teem 2 | Go Module providing an interface for F5's TEEM infrastructure to provide usage analytics to F5. 3 | 4 | # Usage (Anonymous API) 5 | 6 | ```go 7 | 8 | package main 9 | 10 | import ( 11 | //"github.com/RavinderReddyF5/f5-teem" 12 | "github.com/f5devcentral/go-bigip/f5teem" 13 | "log" 14 | ) 15 | 16 | func main() { 17 | assetInfo := f5teem.AssetInfo{ 18 | "Terraform-Provider-BIGIP-Ecosystem", 19 | "1.2.0", 20 | "", 21 | } 22 | teemDevice := f5teem.AnonymousClient(assetInfo, "") 23 | d := map[string]interface{}{ 24 | "Device": 1, 25 | "Tenant": 1, 26 | "License": 1, 27 | "DNS": 1, 28 | "NTP": 1, 29 | "Provision": 1, 30 | "VLAN": 2, 31 | "SelfIp": 2, 32 | "platform": "BIG-IP", 33 | "platformVersion": "15.1.0.5", 34 | } 35 | err := teemDevice.Report(d, "Terraform BIGIP-ravinder-latest", "1") 36 | if err != nil { 37 | log.Printf("Error:%v", err) 38 | } 39 | } 40 | ``` 41 | # Example Telemetry Record 42 | ``` 43 | { 44 | "digitalAssetName": "f5-example-product", 45 | "digitalAssetVersion": "1.0.0", 46 | "digitalAssetId": "", 47 | "documentType": "Installation Usage", 48 | "documentVersion": "1", 49 | "observationStartTime": "", 50 | "observationEndTime": "", 51 | "epochTime": "", 52 | "telemetryId": "", 53 | "telemetryRecords": [ 54 | { 55 | "Device": 1, 56 | "Tenant": 1, 57 | "License": 1, 58 | "DNS": 1, 59 | "NTP": 1, 60 | "Provision": 1, 61 | "VLAN": 2, 62 | "SelfIp": 2, 63 | "platform": "BIG-IP", 64 | "platformVersion": "15.1.0.5", 65 | }] 66 | } 67 | ``` 68 | # Use TEEM staging environment 69 | Set environment variable 70 | ``` 71 | export TEEM_API_ENVIRONMENT='staging' 72 | ``` 73 | # Additional Notes 74 | This library is similar to the node-based f5-teem library (https://www.npmjs.com/package/@f5devcentral/f5-teem), 75 | python library(https://pypi.org/project/f5-teem/) 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [//]: # (Original work Copyright © 2015 Scott Ware) 3 | [//]: # (Modifications Copyright 2019 F5 Networks Inc) 4 | [//]: # (Licensed under the Apache License, Version 2.0 [the "License"];) 5 | [//]: # (You may not use this file except in compliance with the License.) 6 | [//]: # (You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0) 7 | [//]: # (Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,) 8 | [//]: # (WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.) 9 | [//]: # (See the License for the specific language governing permissions and limitations under the License.) 10 | 11 | ## go-bigip 12 | [![GoDoc](https://godoc.org/github.com/f5devcentral/go-bigip?status.svg)](https://godoc.org/github.com/f5devcentral/go-bigip) [![Travis-CI](https://travis-ci.org/f5devcentral/go-bigip.svg?branch=master)](https://travis-ci.org/f5devcentral/go-bigip) 13 | [![Go Report Card](https://goreportcard.com/badge/github.com/f5devcentral/go-bigip)](https://goreportcard.com/report/github.com/f5devcentral/go-bigip) 14 | [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/f5devcentral/go-bigip/master/LICENSE) 15 | 16 | A Go package that interacts with F5 BIG-IP systems using the REST API. 17 | 18 | Some of the tasks you can do are as follows: 19 | 20 | * Get a detailed list of all nodes, pools, vlans, routes, trunks, route domains, self IP's, virtual servers, monitors on the BIG-IP system. 21 | * Create/delete nodes, pools, vlans, routes, trunks, route domains, self IP's, virtual servers, monitors, etc. 22 | * Modify individual settings for all of the above. 23 | * Change the status of nodes and individual pool members (enable/disable). 24 | 25 | > **Note**: You must be on version 11.4+! For the features that deal with internal data groups, you must be running version 11.6+! 26 | 27 | ### Examples & Documentation 28 | Visit the [GoDoc][godoc-go-bigip] page for package documentation and examples. 29 | 30 | Here's a [blog post][blog] that goes a little more in-depth. 31 | 32 | ### Contributors 33 | A very special thanks to the following who have helped contribute to this software, especially: 34 | 35 | * [Adam Burnett](https://github.com/aburnett) 36 | * [Michael D. Ivey](https://github.com/ivey) 37 | 38 | [godoc-go-bigip]: http://godoc.org/github.com/f5devcentral/go-bigip 39 | [license]: https://github.com/f5devcentral/go-bigip/blob/master/LICENSE 40 | [blog]: http://sdubs.org/go-big-ip-or-go-home/ 41 | -------------------------------------------------------------------------------- /examples/go-bigip_example.go: -------------------------------------------------------------------------------- 1 | package bigip 2 | 3 | import ( 4 | "fmt" 5 | "github.com/f5devcentral/go-bigip" 6 | ) 7 | 8 | func main() { 9 | // Connect to the BIG-IP system. 10 | f5 := bigip.NewSession("ltm.company.com", "admin", "secret", nil) 11 | 12 | // Get a list of all VLAN's, and print their names to the console. 13 | vlans, err := f5.Vlans() 14 | if err != nil { 15 | fmt.Println(err) 16 | } 17 | 18 | for _, vlan := range vlans.Vlans { 19 | fmt.Println(vlan.Name) 20 | } 21 | 22 | // Create a VLAN 23 | f5.CreateVlan("vlan1138", 1138) 24 | f5.CreateVlan("vlan421", 421) 25 | 26 | // Add an untagged interface to a VLAN. 27 | f5.AddInterfaceToVlan("vlan1138", "1.2", false) 28 | 29 | // Delete a VLAN. 30 | f5.DeleteVlan("vlan1138") 31 | 32 | // Create a couple of nodes. 33 | f5.CreateNode("web-server-1", "192.168.1.50") 34 | f5.CreateNode("web-server-2", "192.168.1.51") 35 | f5.CreateNode("ssl-web-server-1", "10.2.2.50") 36 | f5.CreateNode("ssl-web-server-2", "10.2.2.51") 37 | 38 | // Create a pool, and add members to it. When adding a member, you must 39 | // specify the port in the format of :. 40 | f5.CreatePool("web_farm_80_pool") 41 | f5.AddPoolMember("web_farm_80_pool", "web-server-1:80") 42 | f5.AddPoolMember("web_farm_80_pool", "web-server-2:80") 43 | f5.CreatePool("ssl_443_pool") 44 | f5.AddPoolMember("ssl_443_pool", "ssl-web-server-1:443") 45 | f5.AddPoolMember("ssl_443_pool", "ssl-web-server-2:443") 46 | 47 | // Create a monitor, and assign it to a pool. 48 | f5.CreateMonitor("web_http_monitor", "http", 5, 16, "GET /\r\n", "200 OK", "http") 49 | f5.AddMonitorToPool("web_http_monitor", "web_farm_80_pool") 50 | 51 | // Create a virtual server, with the above pool. The third field is the subnet 52 | // mask, and that can either be in CIDR notation or decimal. For any/all destinations 53 | // and ports, use '0' for the mask and/or port. 54 | f5.CreateVirtualServer("web_farm_VS", "0.0.0.0", "0.0.0.0", "web_farm_80_pool", 80) 55 | f5.CreateVirtualServer("ssl_web_farm_VS", "10.1.1.0", "24", "ssl_443_pool", 443) 56 | 57 | // Remove a pool member. 58 | f5.DeletePoolMember("web_farm_80_pool", "web-server-2:80") 59 | 60 | // Create a trunk, with LACP enabled. 61 | f5.CreateTrunk("Aggregated", "1.2, 1.4, 1.6", true) 62 | 63 | // Disable a virtual address. 64 | f5.VirtualAddressStatus("web_farm_VS", "disable") 65 | 66 | // Disable a pool member. 67 | f5.PoolMemberStatus("ssl_443_pool", "ssl-web-server-1:443", "disable") 68 | 69 | // Create a self IP. 70 | f5.CreateSelfIP("vlan1138", "10.10.10.1/24", "vlan1138") 71 | f5.CreateSelfIP("vlan421", "10.10.20.1/25", "vlan421") 72 | 73 | // Add a static route. 74 | f5.CreateRoute("servers", "10.1.1.0/24", "10.50.1.5") 75 | 76 | // Create a route domain. 77 | f5.CreateRouteDomain("vlans", 10, true, "vlan1138, vlan421") 78 | } 79 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/suite/doc.go: -------------------------------------------------------------------------------- 1 | // Package suite contains logic for creating testing suite structs 2 | // and running the methods on those structs as tests. The most useful 3 | // piece of this package is that you can create setup/teardown methods 4 | // on your testing suites, which will run before/after the whole suite 5 | // or individual tests (depending on which interface(s) you 6 | // implement). 7 | // 8 | // A testing suite is usually built by first extending the built-in 9 | // suite functionality from suite.Suite in testify. Alternatively, 10 | // you could reproduce that logic on your own if you wanted (you 11 | // just need to implement the TestingSuite interface from 12 | // suite/interfaces.go). 13 | // 14 | // After that, you can implement any of the interfaces in 15 | // suite/interfaces.go to add setup/teardown functionality to your 16 | // suite, and add any methods that start with "Test" to add tests. 17 | // Methods that do not match any suite interfaces and do not begin 18 | // with "Test" will not be run by testify, and can safely be used as 19 | // helper methods. 20 | // 21 | // Once you've built your testing suite, you need to run the suite 22 | // (using suite.Run from testify) inside any function that matches the 23 | // identity that "go test" is already looking for (i.e. 24 | // func(*testing.T)). 25 | // 26 | // Regular expression to select test suites specified command-line 27 | // argument "-run". Regular expression to select the methods 28 | // of test suites specified command-line argument "-m". 29 | // Suite object has assertion methods. 30 | // 31 | // A crude example: 32 | // // Basic imports 33 | // import ( 34 | // "testing" 35 | // "github.com/stretchr/testify/assert" 36 | // "github.com/stretchr/testify/suite" 37 | // ) 38 | // 39 | // // Define the suite, and absorb the built-in basic suite 40 | // // functionality from testify - including a T() method which 41 | // // returns the current testing context 42 | // type ExampleTestSuite struct { 43 | // suite.Suite 44 | // VariableThatShouldStartAtFive int 45 | // } 46 | // 47 | // // Make sure that VariableThatShouldStartAtFive is set to five 48 | // // before each test 49 | // func (suite *ExampleTestSuite) SetupTest() { 50 | // suite.VariableThatShouldStartAtFive = 5 51 | // } 52 | // 53 | // // All methods that begin with "Test" are run as tests within a 54 | // // suite. 55 | // func (suite *ExampleTestSuite) TestExample() { 56 | // assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) 57 | // suite.Equal(5, suite.VariableThatShouldStartAtFive) 58 | // } 59 | // 60 | // // In order for 'go test' to run this suite, we need to create 61 | // // a normal test function and pass our suite to suite.Run 62 | // func TestExampleTestSuite(t *testing.T) { 63 | // suite.Run(t, new(ExampleTestSuite)) 64 | // } 65 | package suite 66 | -------------------------------------------------------------------------------- /vcmp.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2022 F5 Networks Inc 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | package bigip 13 | 14 | type VcmpGuest struct { 15 | Name string `json:"name,omitempty"` 16 | FullPath string `json:"fullPath,omitempty"` 17 | AllowedSlots []int `json:"allowedSlots,omitempty"` 18 | AssignedSlots []int `json:"assignedSlots,omitempty"` 19 | CoresPerSlot int `json:"coresPerSlot,omitempty"` 20 | Hostname string `json:"hostname,omitempty"` 21 | InitialImage string `json:"initialImage,omitempty"` 22 | InitialHotfix string `json:"initialHotfix,omitempty"` 23 | Slots int `json:"slots,omitempty"` 24 | MinSlots int `json:"minSlots,omitempty"` 25 | ManagementNetwork string `json:"managementNetwork,omitempty"` 26 | ManagementIp string `json:"managementIp,omitempty"` 27 | ManagementGw string `json:"managementGw,omitempty"` 28 | VirtualDisk string `json:"virtualDisk,omitempty"` 29 | Vlans []string `json:"vlans,omitempty"` 30 | State string `json:"state,omitempty"` 31 | SslMode string `json:"sslMode,omitempty"` 32 | } 33 | 34 | type VcmpDisks struct { 35 | Disks []VcmpDisk `json:"items,omitempty"` 36 | } 37 | type VcmpDisk struct { 38 | Name string `json:"name,omitempty"` 39 | FullPath string `json:"fullPath,omitempty"` 40 | } 41 | 42 | type VcmpGuestStat struct { 43 | NestedStats struct { 44 | Entries struct { 45 | RequestedState struct { 46 | Descrption string `json:"description,omitempty"` 47 | } `json:"requestedState,omitempty"` 48 | VmStatus struct { 49 | Descrption string `json:"description,omitempty"` 50 | } `json:"vmStatus,omitempty"` 51 | } `json:"entries,omitempty"` 52 | } `json:"nestedStats,omitempty"` 53 | } 54 | type VcmpGuestStats struct { 55 | Kind string `json:"kind,omitempty"` 56 | SelfLink string `json:"selfLink,omitempty"` 57 | Entries DynStat `json:"entries,omitempty"` 58 | } 59 | 60 | type DynStat map[string]VcmpGuestStat 61 | 62 | const ( 63 | uriVcmp = "vcmp" 64 | uriGuest = "guest" 65 | uriDisk = "virtual-disk" 66 | uriStats = "stats" 67 | ) 68 | 69 | func (b *BigIP) GetVcmpGuestStats(name string) (*VcmpGuestStats, error) { 70 | var stats VcmpGuestStats 71 | err, ok := b.getForEntity(&stats, uriVcmp, uriGuest, name, uriStats) 72 | 73 | if err != nil { 74 | return nil, err 75 | } 76 | if !ok { 77 | return nil, nil 78 | } 79 | 80 | return &stats, nil 81 | } 82 | 83 | func (b *BigIP) GetVcmpGuest(name string) (*VcmpGuest, error) { 84 | var guest VcmpGuest 85 | err, _ := b.getForEntity(&guest, uriVcmp, uriGuest, name) 86 | 87 | if err != nil { 88 | return nil, err 89 | } 90 | return &guest, nil 91 | } 92 | 93 | func (b *BigIP) GetVcmpDisks() (*VcmpDisks, error) { 94 | var disks VcmpDisks 95 | err, ok := b.getForEntity(&disks, uriVcmp, uriDisk) 96 | 97 | if err != nil { 98 | return nil, err 99 | } 100 | if !ok { 101 | return nil, nil 102 | } 103 | 104 | return &disks, nil 105 | } 106 | 107 | func (b *BigIP) DeleteVcmpDisk(name string) error { 108 | return b.delete(uriVcmp, uriDisk, name) 109 | } 110 | 111 | func (b *BigIP) CreateVcmpGuest(config *VcmpGuest) error { 112 | return b.post(config, uriVcmp, uriGuest) 113 | } 114 | 115 | func (b *BigIP) UpdateVcmpGuest(name string, config *VcmpGuest) error { 116 | return b.patch(config, uriVcmp, uriGuest, name) 117 | } 118 | 119 | func (b *BigIP) DeleteVcmpGuest(name string) error { 120 | return b.delete(uriVcmp, uriGuest, name) 121 | } 122 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/suite/suite.go: -------------------------------------------------------------------------------- 1 | package suite 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | "reflect" 8 | "regexp" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | var allTestsFilter = func(_, _ string) (bool, error) { return true, nil } 16 | var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run") 17 | 18 | // Suite is a basic testing suite with methods for storing and 19 | // retrieving the current *testing.T context. 20 | type Suite struct { 21 | *assert.Assertions 22 | require *require.Assertions 23 | t *testing.T 24 | } 25 | 26 | // T retrieves the current *testing.T context. 27 | func (suite *Suite) T() *testing.T { 28 | return suite.t 29 | } 30 | 31 | // SetT sets the current *testing.T context. 32 | func (suite *Suite) SetT(t *testing.T) { 33 | suite.t = t 34 | suite.Assertions = assert.New(t) 35 | suite.require = require.New(t) 36 | } 37 | 38 | // Require returns a require context for suite. 39 | func (suite *Suite) Require() *require.Assertions { 40 | if suite.require == nil { 41 | suite.require = require.New(suite.T()) 42 | } 43 | return suite.require 44 | } 45 | 46 | // Assert returns an assert context for suite. Normally, you can call 47 | // `suite.NoError(expected, actual)`, but for situations where the embedded 48 | // methods are overridden (for example, you might want to override 49 | // assert.Assertions with require.Assertions), this method is provided so you 50 | // can call `suite.Assert().NoError()`. 51 | func (suite *Suite) Assert() *assert.Assertions { 52 | if suite.Assertions == nil { 53 | suite.Assertions = assert.New(suite.T()) 54 | } 55 | return suite.Assertions 56 | } 57 | 58 | // Run takes a testing suite and runs all of the tests attached 59 | // to it. 60 | func Run(t *testing.T, suite TestingSuite) { 61 | suite.SetT(t) 62 | 63 | if setupAllSuite, ok := suite.(SetupAllSuite); ok { 64 | setupAllSuite.SetupSuite() 65 | } 66 | defer func() { 67 | if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok { 68 | tearDownAllSuite.TearDownSuite() 69 | } 70 | }() 71 | 72 | methodFinder := reflect.TypeOf(suite) 73 | tests := []testing.InternalTest{} 74 | for index := 0; index < methodFinder.NumMethod(); index++ { 75 | method := methodFinder.Method(index) 76 | ok, err := methodFilter(method.Name) 77 | if err != nil { 78 | fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err) 79 | os.Exit(1) 80 | } 81 | if ok { 82 | test := testing.InternalTest{ 83 | Name: method.Name, 84 | F: func(t *testing.T) { 85 | parentT := suite.T() 86 | suite.SetT(t) 87 | if setupTestSuite, ok := suite.(SetupTestSuite); ok { 88 | setupTestSuite.SetupTest() 89 | } 90 | if beforeTestSuite, ok := suite.(BeforeTest); ok { 91 | beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name) 92 | } 93 | defer func() { 94 | if afterTestSuite, ok := suite.(AfterTest); ok { 95 | afterTestSuite.AfterTest(methodFinder.Elem().Name(), method.Name) 96 | } 97 | if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok { 98 | tearDownTestSuite.TearDownTest() 99 | } 100 | suite.SetT(parentT) 101 | }() 102 | method.Func.Call([]reflect.Value{reflect.ValueOf(suite)}) 103 | }, 104 | } 105 | tests = append(tests, test) 106 | } 107 | } 108 | runTests(t, tests) 109 | } 110 | 111 | func runTests(t testing.TB, tests []testing.InternalTest) { 112 | r, ok := t.(runner) 113 | if !ok { // backwards compatibility with Go 1.6 and below 114 | if !testing.RunTests(allTestsFilter, tests) { 115 | t.Fail() 116 | } 117 | return 118 | } 119 | 120 | for _, test := range tests { 121 | r.Run(test.Name, test.F) 122 | } 123 | } 124 | 125 | // Filtering method according to set regular expression 126 | // specified command-line argument -m 127 | func methodFilter(name string) (bool, error) { 128 | if ok, _ := regexp.MatchString("^Test", name); !ok { 129 | return false, nil 130 | } 131 | return regexp.MatchString(*matchMethod, name) 132 | } 133 | 134 | type runner interface { 135 | Run(name string, f func(t *testing.T)) bool 136 | } 137 | -------------------------------------------------------------------------------- /application.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2019 F5 Networks Inc 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | */ 11 | package bigip 12 | 13 | import ( 14 | //"encoding/json" 15 | "fmt" 16 | "log" 17 | "strings" 18 | ) 19 | 20 | // LIC contains device license for BIG-IP system. 21 | 22 | type Iapps struct { 23 | Iapps []Iapp `json:"items"` 24 | } 25 | 26 | type Iapp struct { 27 | Name string `json:"name,omitempty"` 28 | Partition string `json:"partition,omitempty"` 29 | Description string `json:"description,omitempty"` 30 | DeviceGroup string `json:"deviceGroup,omitempty"` 31 | ExecuteAction string `json:"execute-action,omitempty"` 32 | InheritedDevicegroup string `json:"inheritedDevicegroup,omitempty"` 33 | InheritedTrafficGroup string `json:"inheritedTrafficGroup,omitempty"` 34 | StrictUpdates string `json:"strictUpdates,omitempty"` 35 | Template string `json:"template,omitempty"` 36 | TemplateModified string `json:"templateModified,omitempty"` 37 | TemplatePrerequisiteErrors string `json:"templatePrerequisiteErrors,omitempty"` 38 | TrafficGroup string `json:"trafficGroup,omitempty"` 39 | Jsonfile string `json:"apiAnonymous,omitempty"` 40 | Tables []struct { 41 | ColumnNames []string `json:"columnNames"` 42 | Name string `json:"name"` 43 | Rows []struct { 44 | Row []string `json:"row"` 45 | } `json:"rows"` 46 | } `json:"tables,omitempty"` 47 | 48 | Lists []struct { 49 | Name string `json:"name"` 50 | Encrypted string `json:"encrypted"` 51 | Value []string `json:"value"` 52 | } `json:"lists,omitempty"` 53 | 54 | Variables []struct { 55 | Encrypted string `json:"encrypted"` 56 | Name string `json:"name"` 57 | Value string `json:"value"` 58 | } `json:"variables,omitempty"` 59 | 60 | Metadata []struct { 61 | Persist string `json:"persist"` 62 | Value string `json:"value"` 63 | } `json:"metadata,omitempty"` 64 | } 65 | 66 | const ( 67 | uriApp = "application" 68 | uriService = "service" 69 | uriSysa = "sys" 70 | ) 71 | 72 | func (b *BigIP) CreateIapp(p *Iapp) error { 73 | return b.post(p, uriSysa, uriApp, uriService) 74 | } 75 | 76 | func (b *BigIP) UpdateIapp(name string, p *Iapp) error { 77 | 78 | values := []string{} 79 | values = append(values, fmt.Sprintf("~%s~", p.Partition)) 80 | values = append(values, name) 81 | values = append(values, ".app~") 82 | values = append(values, name) 83 | // Join three strings into one. 84 | result := strings.Join(values, "") 85 | fmt.Println(result) 86 | return b.patch(p, uriSysa, uriApp, uriService, result) 87 | } 88 | 89 | func (b *BigIP) Iapp(name, partition string) (*Iapp, error) { 90 | var iapp Iapp 91 | log.Println(" Value of iapp before read ", &iapp) 92 | values := []string{} 93 | values = append(values, fmt.Sprintf("~%s~", partition)) 94 | values = append(values, name) 95 | values = append(values, ".app~") 96 | values = append(values, name) 97 | // Join three strings into one. 98 | result := strings.Join(values, "") 99 | err, _ := b.getForEntity(&iapp, uriSysa, uriApp, uriService, result) 100 | log.Println(" I am here in sdk with ", err) 101 | if err != nil { 102 | return nil, err 103 | } 104 | log.Println(" Value of iapp after reading ", &iapp) 105 | return &iapp, nil 106 | } 107 | 108 | func (b *BigIP) DeleteIapp(name, partition string) error { 109 | values := []string{} 110 | values = append(values, fmt.Sprintf("~%s~", partition)) 111 | values = append(values, name) 112 | values = append(values, ".app~") 113 | values = append(values, name) 114 | // Join three strings into one. 115 | result := strings.Join(values, "") 116 | return b.delete(uriSys, uriApp, uriService, result) 117 | } 118 | -------------------------------------------------------------------------------- /f5teem/f5teem.go: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 F5 Networks, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package f5teem 17 | 18 | import ( 19 | "bytes" 20 | "crypto/md5" 21 | "crypto/tls" 22 | "encoding/json" 23 | "fmt" 24 | uuid "github.com/google/uuid" 25 | "io" 26 | "io/ioutil" 27 | "net/http" 28 | "os" 29 | "time" 30 | ) 31 | 32 | func AnonymousClient(assetInfo AssetInfo, apiKey string) *TeemObject { 33 | envTeem, teemServer := getEndpointInfo() 34 | if envTeem != "staging" { 35 | apiKey = teemServer.(map[string]string)["api_key"] 36 | } 37 | serviceHost := teemServer.(map[string]string)["endpoint"] 38 | //log.Printf("[INFO]TeemServer:%+v\n", serviceHost) 39 | teemClient := TeemObject{ 40 | assetInfo, 41 | apiKey, 42 | "", 43 | "", 44 | serviceHost, 45 | } 46 | //log.Printf("teemClient:%v\n", teemClient) 47 | return &teemClient 48 | } 49 | 50 | func getEndpointInfo() (string, interface{}) { 51 | environment := envVar["published"].([]string)[0] 52 | if len(os.Getenv(envVar["env_var"].(string))) > 0 { 53 | environment = os.Getenv(envVar["env_var"].(string)) 54 | } 55 | return environment, endPoints["anonymous"].(map[string]interface{})[environment] 56 | } 57 | 58 | func inDocker() bool { 59 | if _, err := os.Stat("/.dockerenv"); err == nil { 60 | return true 61 | } 62 | return false 63 | } 64 | 65 | func genUUID() string { 66 | id := uuid.New() 67 | return id.String() 68 | } 69 | 70 | var osHostname = os.Hostname 71 | 72 | func uniqueUUID() string { 73 | hostname, err := osHostname() 74 | hash := md5.New() 75 | if err != nil { 76 | return genUUID() 77 | } 78 | _, _ = io.WriteString(hash, hostname) 79 | seed := hash.Sum(nil) 80 | uid, err := uuid.FromBytes(seed[0:16]) 81 | if err != nil { 82 | return genUUID() 83 | } 84 | result := uid.String() 85 | return result 86 | } 87 | 88 | func (b *TeemObject) Report(telemetry map[string]interface{}, telemetryType, telemetryTypeVersion string) error { 89 | tr := &http.Transport{ 90 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} 91 | client := &http.Client{Transport: tr} 92 | url := fmt.Sprintf("https://%s/ee/v1/telemetry", b.ServiceHost) 93 | 94 | uniqueID := uniqueUUID() 95 | //log.Printf("[DEBUG] digitalAssetId:%+v", uniqueID) 96 | telemetry["RunningInDocker"] = inDocker() 97 | b.TelemetryType = telemetryType 98 | b.TelemetryTypeVersion = telemetryTypeVersion 99 | //telemetryData, _ := json.Marshal(telemetry) 100 | //telemetryDatalist := []string{string(telemetryData[:])} 101 | //log.Printf("[DEBUG] telemetryDatalist:%+v", telemetryDatalist) 102 | // 103 | //log.Printf("[DEBUG] ControllerAsDocker:#{docker}") 104 | 105 | telemetrynew := []map[string]interface{}{} 106 | telemetrynew = append(telemetrynew, telemetry) 107 | 108 | bodyData := map[string]interface{}{ 109 | "documentType": b.TelemetryType, 110 | "documentVersion": b.TelemetryTypeVersion, 111 | "digitalAssetId": uniqueID, 112 | "digitalAssetName": b.ClientInfo.Name, 113 | "digitalAssetVersion": b.ClientInfo.Version, 114 | "observationStartTime": time.Now().UTC().Format(time.RFC3339Nano), 115 | "observationEndTime": time.Now().UTC().Format(time.RFC3339Nano), 116 | "epochTime": time.Now().Unix(), 117 | "telemetryRecords": telemetrynew, 118 | } 119 | bodyInfo, _ := json.Marshal(bodyData) 120 | body := bytes.NewReader([]byte(bodyInfo)) 121 | req, err := http.NewRequest("POST", url, body) 122 | if err != nil { 123 | fmt.Printf("Error found:%v", err) 124 | } 125 | req.Header.Set("Accept", "application/json") 126 | req.Header.Set("Content-Type", "application/json") 127 | req.Header.Set("F5-ApiKey", b.ApiKey) 128 | req.Header.Set("F5-DigitalAssetId", uniqueID) 129 | req.Header.Set("F5-TraceId", genUUID()) 130 | 131 | //fmt.Printf("Req is :%+v\n", req) 132 | resp, err := client.Do(req) 133 | if err != nil { 134 | return fmt.Errorf("telemetry request to teem server failed with :%v", err) 135 | } 136 | //log.Printf("Resp Code:%+v \t Status:%+v\n", resp.StatusCode, resp.Status) 137 | defer resp.Body.Close() 138 | data, _ := ioutil.ReadAll(resp.Body) 139 | if resp.StatusCode != 204 { 140 | return fmt.Errorf("telemetry request to teem server failed with:%v", string(data[:])) 141 | } 142 | //log.Printf("Resp Body:%v", string(data[:])) 143 | return nil 144 | } 145 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/http_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/httptest" 7 | "net/url" 8 | "strings" 9 | ) 10 | 11 | // httpCode is a helper that returns HTTP code of the response. It returns -1 and 12 | // an error if building a new request fails. 13 | func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { 14 | w := httptest.NewRecorder() 15 | req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) 16 | if err != nil { 17 | return -1, err 18 | } 19 | handler(w, req) 20 | return w.Code, nil 21 | } 22 | 23 | // HTTPSuccess asserts that a specified handler returns a success status code. 24 | // 25 | // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) 26 | // 27 | // Returns whether the assertion was successful (true) or not (false). 28 | func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 29 | code, err := httpCode(handler, method, url, values) 30 | if err != nil { 31 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 32 | return false 33 | } 34 | 35 | isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent 36 | if !isSuccessCode { 37 | Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code)) 38 | } 39 | 40 | return isSuccessCode 41 | } 42 | 43 | // HTTPRedirect asserts that a specified handler returns a redirect status code. 44 | // 45 | // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 46 | // 47 | // Returns whether the assertion was successful (true) or not (false). 48 | func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 49 | code, err := httpCode(handler, method, url, values) 50 | if err != nil { 51 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 52 | return false 53 | } 54 | 55 | isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect 56 | if !isRedirectCode { 57 | Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code)) 58 | } 59 | 60 | return isRedirectCode 61 | } 62 | 63 | // HTTPError asserts that a specified handler returns an error status code. 64 | // 65 | // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 66 | // 67 | // Returns whether the assertion was successful (true) or not (false). 68 | func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 69 | code, err := httpCode(handler, method, url, values) 70 | if err != nil { 71 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) 72 | return false 73 | } 74 | 75 | isErrorCode := code >= http.StatusBadRequest 76 | if !isErrorCode { 77 | Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code)) 78 | } 79 | 80 | return isErrorCode 81 | } 82 | 83 | // HTTPBody is a helper that returns HTTP body of the response. It returns 84 | // empty string if building a new request fails. 85 | func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { 86 | w := httptest.NewRecorder() 87 | req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) 88 | if err != nil { 89 | return "" 90 | } 91 | handler(w, req) 92 | return w.Body.String() 93 | } 94 | 95 | // HTTPBodyContains asserts that a specified handler returns a 96 | // body that contains a string. 97 | // 98 | // assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") 99 | // 100 | // Returns whether the assertion was successful (true) or not (false). 101 | func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 102 | body := HTTPBody(handler, method, url, values) 103 | 104 | contains := strings.Contains(body, fmt.Sprint(str)) 105 | if !contains { 106 | Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) 107 | } 108 | 109 | return contains 110 | } 111 | 112 | // HTTPBodyNotContains asserts that a specified handler returns a 113 | // body that does not contain a string. 114 | // 115 | // assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") 116 | // 117 | // Returns whether the assertion was successful (true) or not (false). 118 | func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 119 | body := HTTPBody(handler, method, url, values) 120 | 121 | contains := strings.Contains(body, fmt.Sprint(str)) 122 | if contains { 123 | Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) 124 | } 125 | 126 | return !contains 127 | } 128 | -------------------------------------------------------------------------------- /utility.go: -------------------------------------------------------------------------------- 1 | /* 2 | Original work Copyright © 2015 Scott Ware 3 | Modifications Copyright 2019 F5 Networks Inc 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | You may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | */ 11 | package bigip 12 | 13 | import "encoding/json" 14 | 15 | // LIC contains device license for BIG-IP system. 16 | type ULICs struct { 17 | LIC []LIC `json:"items"` 18 | } 19 | 20 | // This is BIG-IP which needs to be licensed. 21 | type ULIC struct { 22 | DeviceAddress string 23 | Username string 24 | Password string 25 | UnitOfMeasure string 26 | } 27 | 28 | type UtilityPools struct { 29 | UtilityPool []UtilityPool `json:"items"` 30 | } 31 | 32 | type UtilityPool struct { 33 | Items []struct { 34 | RegKey string `json:"RegKey,omitempty"` 35 | } 36 | } 37 | 38 | type ULICDTO struct { 39 | DeviceAddress string `json:"deviceAddress,omitempty"` 40 | Username string `json:"username,omitempty"` 41 | Password string `json:"password,omitempty"` 42 | UnitOfMeasure string `json:"unitOfMeasure,omitempty"` 43 | } 44 | 45 | /*GET https://10.192.74.92/mgmt/cm/device/licensing/pool/utility/licenses 46 | 47 | To view a particular utility license (exclude brackets) 48 | GET https://10.192.74.92/mgmt/cm/device/licensing/pool/utility/licenses/{ reg key for license} 49 | So for your license currently on box 50 | GET https://10.192.74.92/mgmt/cm/device/licensing/pool/utility/licenses/FDKOC-UVGUE-FDURD-AYYDH-IXDSOYV 51 | 52 | To view the list of offerings for a utility license 53 | GET https://10.192.74.92/mgmt/cm/device/licensing/pool/utility/licenses/FDKOC-UVGUE-FDURD-AYYDH-IXDSOYV/offerings 54 | 55 | To view the members of an offering 56 | GET https://10.192.74.92/mgmt/cm/device/licensing/pool/utility/licenses/{RegKey}/offerings/{offering id}/members 57 | So for your license currently on box 58 | GET https://10.192.74.92/mgmt/cm/device/licensing/pool/utility/licenses/FDKOC-UVGUE-FDURD-AYYDH-IXDSOYV/offerings/fb7b7c65-5551-4ab2-a35a-659d47533e6b/members 59 | 60 | To assign a license a device the license from an offering you would POST to the members collection like you would for purchased pool licenses for managed devices. 61 | POST https://10.192.74.92/mgmt/cm/device/licensing/pool/utility/licenses/FDKOC-UVGUE-FDURD-AYYDH-IXDSOYV/offerings/fb7b7c65-5551-4ab2-a35a-659d47533e6b/members 62 | { 63 | 64 | “unitOfMeasure”: “yearly” 65 | } 66 | UnitOfMeasure can be “hourly”,”daily”, “monthly”, “yearly”. 67 | 68 | */ 69 | 70 | func (p *ULIC) MarshalJSON() ([]byte, error) { 71 | var dto ULICDTO 72 | marshal(&dto, p) 73 | return json.Marshal(dto) 74 | } 75 | 76 | func (p *ULIC) UnmarshalJSON(b []byte) error { 77 | var dto ULICDTO 78 | err := json.Unmarshal(b, &dto) 79 | if err != nil { 80 | return err 81 | } 82 | return marshal(p, &dto) 83 | } 84 | 85 | // Get the RegKey which is used to know what Bulk license is available on BIG-IQ 86 | func (b *BigIP) getUtilityPool() (*UtilityPool, error) { 87 | var utilityPool UtilityPool 88 | err, _ := b.getForEntity(&utilityPool, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriUtility, uriLicn) 89 | if err != nil { 90 | return nil, err 91 | } 92 | // for loop over all returned license pools to check which one has available licenses 93 | // getAvailablePool(member[index_of_array].Uuid) 94 | // At the end change return statement to return only the UUID string of the one where license 95 | // is available 96 | return &utilityPool, nil 97 | } 98 | 99 | // Function to get the RegKey 100 | func (b *BigIP) ULIC() (*ULIC, error) { 101 | var va ULIC 102 | utilityPool, utilityPoolErr := b.getUtilityPool() 103 | if utilityPoolErr != nil { 104 | return nil, utilityPoolErr 105 | } 106 | err, _ := b.getForEntity(&va, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriUtility, uriLicn, utilityPool.Items[0].RegKey) 107 | if err != nil { 108 | return nil, err 109 | } 110 | return &va, nil 111 | } 112 | 113 | func (b *BigIP) CreateULIC(deviceAddress string, username string, password string, unitOfMeasure string) error { 114 | config := &ULIC{ 115 | DeviceAddress: deviceAddress, 116 | Username: username, 117 | Password: password, 118 | UnitOfMeasure: unitOfMeasure, 119 | } 120 | 121 | utilityPool, utilityPoolErr := b.getUtilityPool() 122 | if utilityPoolErr != nil { 123 | return utilityPoolErr 124 | } 125 | 126 | return b.post(config, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriUtility, uriLicn, utilityPool.Items[0].RegKey, uriOfferings, uriF5BIGMSPBT10G, uriMemb) 127 | } 128 | 129 | func (b *BigIP) ModifyULIC(config *ULIC) error { 130 | utilityPool, utilityPoolErr := b.getUtilityPool() 131 | if utilityPoolErr != nil { 132 | return utilityPoolErr 133 | } 134 | return b.patch(config, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriUtility, uriLicn, utilityPool.Items[0].RegKey, uriMemb) 135 | } 136 | 137 | func (b *BigIP) ULICs() (*ULIC, error) { 138 | var members ULIC 139 | utilityPool, utilityPoolErr := b.getUtilityPool() 140 | if utilityPoolErr != nil { 141 | return nil, utilityPoolErr 142 | } 143 | err, _ := b.getForEntity(&members, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriUtility, uriLicn, utilityPool.Items[0].RegKey, uriMemb) 144 | 145 | if err != nil { 146 | return nil, err 147 | } 148 | 149 | return &members, nil 150 | } 151 | 152 | func (b *BigIP) DeleteULIC(config *ULIC) error { 153 | 154 | utilityPool, utilityPoolErr := b.getUtilityPool() 155 | if utilityPoolErr != nil { 156 | return utilityPoolErr 157 | } 158 | 159 | return b.delete(uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriUtility, uriLicn, utilityPool.Items[0].RegKey, uriOfferings, uriF5BIGMSPBT10G, uriMemb) 160 | } 161 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypass.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is not running on Google App Engine, compiled by GopherJS, and 17 | // "-tags safe" is not added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build !js,!appengine,!safe,!disableunsafe 20 | 21 | package spew 22 | 23 | import ( 24 | "reflect" 25 | "unsafe" 26 | ) 27 | 28 | const ( 29 | // UnsafeDisabled is a build-time constant which specifies whether or 30 | // not access to the unsafe package is available. 31 | UnsafeDisabled = false 32 | 33 | // ptrSize is the size of a pointer on the current arch. 34 | ptrSize = unsafe.Sizeof((*byte)(nil)) 35 | ) 36 | 37 | var ( 38 | // offsetPtr, offsetScalar, and offsetFlag are the offsets for the 39 | // internal reflect.Value fields. These values are valid before golang 40 | // commit ecccf07e7f9d which changed the format. The are also valid 41 | // after commit 82f48826c6c7 which changed the format again to mirror 42 | // the original format. Code in the init function updates these offsets 43 | // as necessary. 44 | offsetPtr = uintptr(ptrSize) 45 | offsetScalar = uintptr(0) 46 | offsetFlag = uintptr(ptrSize * 2) 47 | 48 | // flagKindWidth and flagKindShift indicate various bits that the 49 | // reflect package uses internally to track kind information. 50 | // 51 | // flagRO indicates whether or not the value field of a reflect.Value is 52 | // read-only. 53 | // 54 | // flagIndir indicates whether the value field of a reflect.Value is 55 | // the actual data or a pointer to the data. 56 | // 57 | // These values are valid before golang commit 90a7c3c86944 which 58 | // changed their positions. Code in the init function updates these 59 | // flags as necessary. 60 | flagKindWidth = uintptr(5) 61 | flagKindShift = uintptr(flagKindWidth - 1) 62 | flagRO = uintptr(1 << 0) 63 | flagIndir = uintptr(1 << 1) 64 | ) 65 | 66 | func init() { 67 | // Older versions of reflect.Value stored small integers directly in the 68 | // ptr field (which is named val in the older versions). Versions 69 | // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named 70 | // scalar for this purpose which unfortunately came before the flag 71 | // field, so the offset of the flag field is different for those 72 | // versions. 73 | // 74 | // This code constructs a new reflect.Value from a known small integer 75 | // and checks if the size of the reflect.Value struct indicates it has 76 | // the scalar field. When it does, the offsets are updated accordingly. 77 | vv := reflect.ValueOf(0xf00) 78 | if unsafe.Sizeof(vv) == (ptrSize * 4) { 79 | offsetScalar = ptrSize * 2 80 | offsetFlag = ptrSize * 3 81 | } 82 | 83 | // Commit 90a7c3c86944 changed the flag positions such that the low 84 | // order bits are the kind. This code extracts the kind from the flags 85 | // field and ensures it's the correct type. When it's not, the flag 86 | // order has been changed to the newer format, so the flags are updated 87 | // accordingly. 88 | upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) 89 | upfv := *(*uintptr)(upf) 90 | flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { 92 | flagKindShift = 0 93 | flagRO = 1 << 5 94 | flagIndir = 1 << 6 95 | 96 | // Commit adf9b30e5594 modified the flags to separate the 97 | // flagRO flag into two bits which specifies whether or not the 98 | // field is embedded. This causes flagIndir to move over a bit 99 | // and means that flagRO is the combination of either of the 100 | // original flagRO bit and the new bit. 101 | // 102 | // This code detects the change by extracting what used to be 103 | // the indirect bit to ensure it's set. When it's not, the flag 104 | // order has been changed to the newer format, so the flags are 105 | // updated accordingly. 106 | if upfv&flagIndir == 0 { 107 | flagRO = 3 << 5 108 | flagIndir = 1 << 7 109 | } 110 | } 111 | } 112 | 113 | // unsafeReflectValue converts the passed reflect.Value into a one that bypasses 114 | // the typical safety restrictions preventing access to unaddressable and 115 | // unexported data. It works by digging the raw pointer to the underlying 116 | // value out of the protected value and generating a new unprotected (unsafe) 117 | // reflect.Value to it. 118 | // 119 | // This allows us to check for implementations of the Stringer and error 120 | // interfaces to be used for pretty printing ordinarily unaddressable and 121 | // inaccessible values such as unexported struct fields. 122 | func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { 123 | indirects := 1 124 | vt := v.Type() 125 | upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) 126 | rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) 127 | if rvf&flagIndir != 0 { 128 | vt = reflect.PtrTo(v.Type()) 129 | indirects++ 130 | } else if offsetScalar != 0 { 131 | // The value is in the scalar field when it's not one of the 132 | // reference types. 133 | switch vt.Kind() { 134 | case reflect.Uintptr: 135 | case reflect.Chan: 136 | case reflect.Func: 137 | case reflect.Map: 138 | case reflect.Ptr: 139 | case reflect.UnsafePointer: 140 | default: 141 | upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + 142 | offsetScalar) 143 | } 144 | } 145 | 146 | pv := reflect.NewAt(vt, upv) 147 | rv = pv 148 | for i := 0; i < indirects; i++ { 149 | rv = rv.Elem() 150 | } 151 | return rv 152 | } 153 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/spew.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | ) 23 | 24 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 25 | // passed with a default Formatter interface returned by NewFormatter. It 26 | // returns the formatted string as a value that satisfies error. See 27 | // NewFormatter for formatting details. 28 | // 29 | // This function is shorthand for the following syntax: 30 | // 31 | // fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 32 | func Errorf(format string, a ...interface{}) (err error) { 33 | return fmt.Errorf(format, convertArgs(a)...) 34 | } 35 | 36 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 37 | // passed with a default Formatter interface returned by NewFormatter. It 38 | // returns the number of bytes written and any write error encountered. See 39 | // NewFormatter for formatting details. 40 | // 41 | // This function is shorthand for the following syntax: 42 | // 43 | // fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) 44 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) { 45 | return fmt.Fprint(w, convertArgs(a)...) 46 | } 47 | 48 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 49 | // passed with a default Formatter interface returned by NewFormatter. It 50 | // returns the number of bytes written and any write error encountered. See 51 | // NewFormatter for formatting details. 52 | // 53 | // This function is shorthand for the following syntax: 54 | // 55 | // fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) 56 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 57 | return fmt.Fprintf(w, format, convertArgs(a)...) 58 | } 59 | 60 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 61 | // passed with a default Formatter interface returned by NewFormatter. See 62 | // NewFormatter for formatting details. 63 | // 64 | // This function is shorthand for the following syntax: 65 | // 66 | // fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) 67 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 68 | return fmt.Fprintln(w, convertArgs(a)...) 69 | } 70 | 71 | // Print is a wrapper for fmt.Print that treats each argument as if it were 72 | // passed with a default Formatter interface returned by NewFormatter. It 73 | // returns the number of bytes written and any write error encountered. See 74 | // NewFormatter for formatting details. 75 | // 76 | // This function is shorthand for the following syntax: 77 | // 78 | // fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) 79 | func Print(a ...interface{}) (n int, err error) { 80 | return fmt.Print(convertArgs(a)...) 81 | } 82 | 83 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 84 | // passed with a default Formatter interface returned by NewFormatter. It 85 | // returns the number of bytes written and any write error encountered. See 86 | // NewFormatter for formatting details. 87 | // 88 | // This function is shorthand for the following syntax: 89 | // 90 | // fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 91 | func Printf(format string, a ...interface{}) (n int, err error) { 92 | return fmt.Printf(format, convertArgs(a)...) 93 | } 94 | 95 | // Println is a wrapper for fmt.Println that treats each argument as if it were 96 | // passed with a default Formatter interface returned by NewFormatter. It 97 | // returns the number of bytes written and any write error encountered. See 98 | // NewFormatter for formatting details. 99 | // 100 | // This function is shorthand for the following syntax: 101 | // 102 | // fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) 103 | func Println(a ...interface{}) (n int, err error) { 104 | return fmt.Println(convertArgs(a)...) 105 | } 106 | 107 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 108 | // passed with a default Formatter interface returned by NewFormatter. It 109 | // returns the resulting string. See NewFormatter for formatting details. 110 | // 111 | // This function is shorthand for the following syntax: 112 | // 113 | // fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) 114 | func Sprint(a ...interface{}) string { 115 | return fmt.Sprint(convertArgs(a)...) 116 | } 117 | 118 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 119 | // passed with a default Formatter interface returned by NewFormatter. It 120 | // returns the resulting string. See NewFormatter for formatting details. 121 | // 122 | // This function is shorthand for the following syntax: 123 | // 124 | // fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 125 | func Sprintf(format string, a ...interface{}) string { 126 | return fmt.Sprintf(format, convertArgs(a)...) 127 | } 128 | 129 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 130 | // were passed with a default Formatter interface returned by NewFormatter. It 131 | // returns the resulting string. See NewFormatter for formatting details. 132 | // 133 | // This function is shorthand for the following syntax: 134 | // 135 | // fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) 136 | func Sprintln(a ...interface{}) string { 137 | return fmt.Sprintln(convertArgs(a)...) 138 | } 139 | 140 | // convertArgs accepts a slice of arguments and returns a slice of the same 141 | // length with each argument converted to a default spew Formatter interface. 142 | func convertArgs(args []interface{}) (formatters []interface{}) { 143 | formatters = make([]interface{}, len(args)) 144 | for index, arg := range args { 145 | formatters[index] = NewFormatter(arg) 146 | } 147 | return formatters 148 | } 149 | -------------------------------------------------------------------------------- /app.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2019 F5 Networks Inc 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | /* 13 | AS3 uses a declarative model, meaning you provide a JSON declaration rather than a set of imperative commands. The declaration represents the configuration which AS3 is responsible for creating on a BIG-IP system. AS3 is well-defined according to the rules of JSON Schema, and declarations validate according to JSON Schema. AS3 accepts declaration updates via REST (push), reference (pull), or CLI (flat file editing). 14 | To read more about As3 check https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/latest/userguide/ 15 | */ 16 | package bigip 17 | 18 | import ( 19 | "log" 20 | ) 21 | 22 | type Appsvcs struct { 23 | Appsvcs []Appsvc01 `json:"items"` 24 | } 25 | type Appsvc01 struct { 26 | Class string `json:"class"` 27 | Action string `json:"action"` 28 | Persist bool `json:"persist"` 29 | Declaration struct { 30 | Class string `json:"class"` 31 | SchemaVersion string `json:"schemaVersion"` 32 | ID string `json:"id"` 33 | Label string `json:"label"` 34 | Remark string `json:"remark"` 35 | Sample01 struct { 36 | Class string `json:"class"` 37 | DefaultRouteDomain int `json:"defaultRouteDomain"` 38 | Application1 struct { 39 | Class string `json:"class"` 40 | Template string `json:"template"` 41 | ServiceMain struct { 42 | Class string `json:"class"` 43 | VirtualAddresses []string `json:"virtualAddresses"` 44 | Pool string `json:"pool"` 45 | } `json:"serviceMain"` 46 | WebPool struct { 47 | Class string `json:"class"` 48 | Monitors []string `json:"monitors"` 49 | Members []struct { 50 | ServicePort int `json:"servicePort"` 51 | ServerAddresses []string `json:"serverAddresses"` 52 | } `json:"members"` 53 | } `json:"web_pool"` 54 | } `json:"Application_1"` 55 | } `json:"Sample_01,omitempty"` 56 | } `json:"declaration,omitempty"` 57 | } 58 | 59 | type Appsvc02 struct { 60 | Class string `json:"class"` 61 | Action string `json:"action"` 62 | Persist bool `json:"persist"` 63 | Declaration struct { 64 | Class string `json:"class"` 65 | SchemaVersion string `json:"schemaVersion"` 66 | ID string `json:"id"` 67 | Label string `json:"label"` 68 | Remark string `json:"remark"` 69 | Sample02 struct { 70 | Class string `json:"class"` 71 | A1 struct { 72 | Class string `json:"class"` 73 | Template string `json:"template"` 74 | ServiceMain struct { 75 | Class string `json:"class"` 76 | VirtualAddresses []string `json:"virtualAddresses"` 77 | Pool string `json:"pool"` 78 | ServerTLS string `json:"serverTLS"` 79 | } `json:"serviceMain"` 80 | WebPool struct { 81 | Class string `json:"class"` 82 | LoadBalancingMode string `json:"loadBalancingMode"` 83 | Monitors []string `json:"monitors"` 84 | Members []struct { 85 | ServicePort int `json:"servicePort"` 86 | ServerAddresses []string `json:"serverAddresses"` 87 | } `json:"members"` 88 | } `json:"web_pool"` 89 | Webtls struct { 90 | Class string `json:"class"` 91 | Certificates []struct { 92 | Certificate string `json:"certificate"` 93 | } `json:"certificates"` 94 | } `json:"webtls"` 95 | Webcert struct { 96 | Class string `json:"class"` 97 | Remark string `json:"remark"` 98 | Certificate string `json:"certificate"` 99 | PrivateKey string `json:"privateKey"` 100 | Passphrase struct { 101 | Ciphertext string `json:"ciphertext"` 102 | Protected string `json:"protected"` 103 | } `json:"passphrase"` 104 | } `json:"webcert"` 105 | } `json:"A1"` 106 | } `json:"Sample_02"` 107 | } `json:"declaration"` 108 | } 109 | 110 | const ( 111 | uriSam01 = "Sample_01" 112 | uriSam02 = "Sample_02" 113 | ) 114 | 115 | // Appsvcss returns a list of appsvcs 116 | func (b *BigIP) Appsvc01() (*Appsvc01, error) { 117 | var appsvc01 Appsvc01 118 | err, _ := b.getForEntity(uriSam01, uriSha, uriAppsvcs, uriDecl) 119 | log.Printf("i am here in sdk %+v ", appsvc01) 120 | if err != nil { 121 | return nil, err 122 | } 123 | 124 | return &appsvc01, nil 125 | } 126 | func (b *BigIP) Appsvc02() (*Appsvc02, error) { 127 | var appsvc02 Appsvc02 128 | err, _ := b.getForEntity(uriSam02, uriSha, uriAppsvcs, uriDecl) 129 | log.Printf("i am here in sdk %+v ", appsvc02) 130 | if err != nil { 131 | return nil, err 132 | } 133 | 134 | return &appsvc02, nil 135 | } 136 | 137 | // CreateAppsvcs creates a new iAppsvcs on the system. 138 | func (b *BigIP) CreateAppsvc01(p *Appsvc01) error { 139 | log.Printf("++++++ Here is what terraform is sending to bigip ................ : %+v ", p) 140 | err := b.post(p, uriMgmt, uriSha, uriAppsvcs, uriDecl) 141 | if err != nil { 142 | log.Println(" API call not successfull ", err) 143 | } 144 | return nil 145 | } 146 | func (b *BigIP) CreateAppsvc02(p *Appsvc02) error { 147 | log.Printf("++++++ Here is what terraform is sending to bigip ................ : %+v ", p) 148 | err := b.post(p, uriMgmt, uriSha, uriAppsvcs, uriDecl) 149 | if err != nil { 150 | log.Println(" API call not successfull ", err) 151 | } 152 | return nil 153 | } 154 | func (b *BigIP) DeleteAppsvc01() error { 155 | return b.delete(uriMgmt, uriSha, uriAppsvcs, uriDecl, uriSam01) 156 | } 157 | func (b *BigIP) DeleteAppsvc02() error { 158 | return b.delete(uriMgmt, uriSha, uriAppsvcs, uriDecl, uriSam02) 159 | } 160 | 161 | func (b *BigIP) ModifyAppsvc01(p *Appsvc01) error { 162 | log.Printf("++++++ Here is what terraform is sending to bigip ................ : %+v ", p) 163 | err := b.patch(p, uriMgmt, uriSha, uriAppsvcs, uriDecl) 164 | log.Println("value of p in modify +++++++++++++++", p) 165 | if err != nil { 166 | log.Println(" API call not successfull ", err) 167 | } 168 | return nil 169 | } 170 | func (b *BigIP) ModifyAppsvc02(p *Appsvc02) error { 171 | log.Printf("++++++ Here is what terraform is sending to bigip ................ : %+v ", p) 172 | err := b.patch(p, uriMgmt, uriSha, uriAppsvcs, uriDecl) 173 | if err != nil { 174 | log.Println(" API call not successfull ", err) 175 | } 176 | return nil 177 | } 178 | -------------------------------------------------------------------------------- /examples/access/test_access_policy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/f5devcentral/go-bigip" 10 | ) 11 | 12 | func testAccessPolicy(f5 *bigip.BigIP) { 13 | 14 | fmt.Println("=== F5 BIG-IP Access Policy CRUD Operations Test ===") 15 | 16 | // Test 1: List all existing Access Policies 17 | fmt.Println("\n1. Listing all existing Access Policies...") 18 | listAccessPolicies(f5) 19 | 20 | // Test 2: Create a new Access Policy 21 | fmt.Println("\n2. Creating a new Access Policy...") 22 | policyName := "test-access-policy" 23 | createAccessPolicy(f5, policyName) 24 | 25 | // Test 3: Get the specific Access Policy we just created 26 | fmt.Println("\n3. Retrieving the created Access Policy...") 27 | getAccessPolicy(f5, policyName) 28 | 29 | // Test 4: Modify the Access Policy 30 | fmt.Println("\n4. Modifying the Access Policy...") 31 | modifyAccessPolicy(f5, policyName) 32 | 33 | // Test 5: Get the modified Access Policy to verify changes 34 | fmt.Println("\n5. Retrieving the modified Access Policy...") 35 | getAccessPolicy(f5, policyName) 36 | 37 | // Test 6: Clean up - Delete the created Access Policy 38 | fmt.Println("\n6. Cleaning up - Deleting created Access Policy...") 39 | deleteAccessPolicy(f5, policyName) 40 | 41 | fmt.Println("\n=== Access Policy CRUD Operations Test Complete ===") 42 | } 43 | 44 | // listAccessPolicies demonstrates how to retrieve all access policies 45 | func listAccessPolicies(f5 *bigip.BigIP) { 46 | // Create a context with timeout to prevent hanging 47 | ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 48 | defer cancel() 49 | 50 | // Use a channel to handle the result 51 | type result struct { 52 | policies *bigip.AccessPolicies 53 | err error 54 | } 55 | 56 | resultChan := make(chan result, 1) 57 | 58 | go func() { 59 | policies, err := f5.AccessPolicies() 60 | resultChan <- result{policies: policies, err: err} 61 | }() 62 | 63 | select { 64 | case res := <-resultChan: 65 | if res.err != nil { 66 | log.Printf("Error retrieving access policies: %v", res.err) 67 | return 68 | } 69 | 70 | if len(res.policies.Items) == 0 { 71 | fmt.Println("No access policies found.") 72 | return 73 | } 74 | 75 | fmt.Printf("Found %d access policy(ies):\n", len(res.policies.Items)) 76 | for i, policy := range res.policies.Items { 77 | fmt.Printf(" %d. Name: %s, Partition: %s, Type: %s\n", 78 | i+1, policy.Name, policy.Partition, policy.Type) 79 | if policy.DefaultEnding != "" { 80 | fmt.Printf(" Default Ending: %s\n", policy.DefaultEnding) 81 | } 82 | fmt.Printf(" Full Path: %s\n", policy.FullPath) 83 | } 84 | case <-ctx.Done(): 85 | fmt.Printf("Timeout: Failed to retrieve access policies within 30 seconds\n") 86 | } 87 | } 88 | 89 | // createAccessPolicy demonstrates how to create a basic access policy 90 | func createAccessPolicy(f5 *bigip.BigIP, name string) { 91 | policy := &bigip.AccessPolicy{ 92 | Name: name, 93 | Partition: "Common", 94 | Type: "per-rq-policy", 95 | DefaultEnding: "allow", // Use simple allow instead of non-existent item 96 | MaxMacroLoopCount: 1, 97 | // StartItem: "fallback", // Add proper start item 98 | PerReqPolicyProperties: []bigip.PerReqPolicyProperty{ 99 | { 100 | Name: "PerReqPolicyProperty", 101 | Partition: "Common", 102 | IncompleteAction: "allow", 103 | }, 104 | }, 105 | } 106 | 107 | ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 108 | defer cancel() 109 | 110 | resultChan := make(chan error, 1) 111 | 112 | go func() { 113 | err := f5.CreateAccessPolicy(policy) 114 | resultChan <- err 115 | }() 116 | 117 | select { 118 | case err := <-resultChan: 119 | if err != nil { 120 | log.Printf("Error creating access policy '%s': %v", name, err) 121 | return 122 | } 123 | fmt.Printf("Successfully created access policy: %s\n", name) 124 | 125 | // Wait a moment for the policy to be fully created 126 | time.Sleep(2 * time.Second) 127 | case <-ctx.Done(): 128 | fmt.Printf("Timeout: Failed to create access policy within 30 seconds\n") 129 | } 130 | } 131 | 132 | // getAccessPolicy demonstrates how to retrieve a specific access policy 133 | func getAccessPolicy(f5 *bigip.BigIP, name string) { 134 | ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 135 | defer cancel() 136 | 137 | type result struct { 138 | policy *bigip.AccessPolicy 139 | err error 140 | } 141 | 142 | resultChan := make(chan result, 1) 143 | 144 | go func() { 145 | policy, err := f5.GetAccessPolicy(name) 146 | resultChan <- result{policy: policy, err: err} 147 | }() 148 | 149 | select { 150 | case res := <-resultChan: 151 | if res.err != nil { 152 | log.Printf("Error retrieving access policy '%s': %v", name, res.err) 153 | return 154 | } 155 | 156 | if res.policy == nil { 157 | fmt.Printf("Access policy '%s' not found.\n", name) 158 | return 159 | } 160 | 161 | fmt.Printf("Access Policy Details:\n") 162 | fmt.Printf(" Name: %s\n", res.policy.Name) 163 | fmt.Printf(" Partition: %s\n", res.policy.Partition) 164 | fmt.Printf(" Full Path: %s\n", res.policy.FullPath) 165 | fmt.Printf(" Type: %s\n", res.policy.Type) 166 | fmt.Printf(" Default Ending: %s\n", res.policy.DefaultEnding) 167 | fmt.Printf(" Max Macro Loop Count: %d\n", res.policy.MaxMacroLoopCount) 168 | fmt.Printf(" Oneshot Macro: %s\n", res.policy.OneshotMacro) 169 | fmt.Printf(" Start Item: %s\n", res.policy.StartItem) 170 | if len(res.policy.PerReqPolicyProperties) > 0 { 171 | fmt.Printf(" Per-Request Policy Properties:\n") 172 | for i, prop := range res.policy.PerReqPolicyProperties { 173 | fmt.Printf(" %d. Name: %s, Partition: %s, Incomplete Action: %s\n", 174 | i+1, prop.Name, prop.Partition, prop.IncompleteAction) 175 | } 176 | } 177 | if res.policy.Generation > 0 { 178 | fmt.Printf(" Generation: %d\n", res.policy.Generation) 179 | } 180 | case <-ctx.Done(): 181 | fmt.Printf("Timeout: Failed to retrieve access policy within 30 seconds\n") 182 | } 183 | } 184 | 185 | // modifyAccessPolicy demonstrates how to modify an existing access policy 186 | func modifyAccessPolicy(f5 *bigip.BigIP, name string) { 187 | currentPolicy, err := f5.GetAccessPolicy(name) 188 | if err != nil { 189 | log.Printf("Error retrieving access policy '%s' for modification: %v", name, err) 190 | return 191 | } 192 | // Create a modified version 193 | currentPolicy.PerReqPolicyProperties[0].IncompleteAction = "deny" 194 | modifiedPolicy := &bigip.AccessPolicy{ 195 | Name: currentPolicy.Name, 196 | Partition: currentPolicy.Partition, 197 | Type: "per-rq-policy", 198 | DefaultEnding: "/Common/test-access-policy_end_reject", 199 | MaxMacroLoopCount: 1, 200 | // Preserve existing PerReqPolicyProperties - don't modify them to avoid deletion error 201 | PerReqPolicyProperties: currentPolicy.PerReqPolicyProperties, 202 | } 203 | 204 | err = f5.ModifyAccessPolicy(name, modifiedPolicy) 205 | if err != nil { 206 | log.Printf("Error modifying access policy '%s': %v", name, err) 207 | return 208 | } 209 | } 210 | 211 | // deleteAccessPolicy demonstrates how to delete an access policy 212 | func deleteAccessPolicy(f5 *bigip.BigIP, name string) { 213 | err := f5.DeleteAccessPolicy(name) 214 | if err != nil { 215 | log.Printf("Error deleting access policy '%s': %v", name, err) 216 | return 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /gtm.go: -------------------------------------------------------------------------------- 1 | /* 2 | Original work Copyright © 2015 Scott Ware 3 | Modifications Copyright 2019 F5 Networks Inc 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | You may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | */ 11 | package bigip 12 | 13 | import ( 14 | "encoding/json" 15 | "log" 16 | ) 17 | 18 | //ooo 19 | 20 | type Datacenters struct { 21 | Datacenters []Datacenter `json:"items"` 22 | } 23 | 24 | type Datacenter struct { 25 | Name string `json:"name,omitempty"` 26 | Description string `json:"description,omitempty"` 27 | Contact string `json:"contact,omitempty"` 28 | App_service string `json:"appService,omitempty"` 29 | Disabled bool `json:"disabled,omitempty"` 30 | Enabled bool `json:"enabled,omitempty"` 31 | Prober_pool string `json:"proberPool,omitempty"` 32 | } 33 | 34 | type Gtmmonitors struct { 35 | Gtmmonitors []Gtmmonitor `json:"items"` 36 | } 37 | 38 | type Gtmmonitor struct { 39 | Name string `json:"name,omitempty"` 40 | Defaults_from string `json:"defaultsFrom,omitempty"` 41 | Interval int `json:"interval,omitempty"` 42 | Probe_timeout int `json:"probeTimeout,omitempty"` 43 | Recv string `json:"recv,omitempty"` 44 | Send string `json:"send,omitempty"` 45 | } 46 | 47 | type Servers struct { 48 | Servers []Server `json:"items"` 49 | } 50 | 51 | type Server struct { 52 | Name string 53 | Datacenter string 54 | Monitor string 55 | Virtual_server_discovery bool 56 | Product string 57 | Addresses []ServerAddresses 58 | GTMVirtual_Server []VSrecord 59 | } 60 | 61 | type serverDTO struct { 62 | Name string `json:"name"` 63 | Datacenter string `json:"datacenter,omitempty"` 64 | Monitor string `json:"monitor,omitempty"` 65 | Virtual_server_discovery bool `json:"virtual_server_discovery"` 66 | Product string `json:"product,omitempty"` 67 | Addresses struct { 68 | Items []ServerAddresses `json:"items,omitempty"` 69 | } `json:"addressesReference,omitempty"` 70 | GTMVirtual_Server struct { 71 | Items []VSrecord `json:"items,omitempty"` 72 | } `json:"virtualServersReference,omitempty"` 73 | } 74 | 75 | func (p *Server) MarshalJSON() ([]byte, error) { 76 | return json.Marshal(serverDTO{ 77 | Name: p.Name, 78 | Datacenter: p.Datacenter, 79 | Monitor: p.Monitor, 80 | Virtual_server_discovery: p.Virtual_server_discovery, 81 | Product: p.Product, 82 | Addresses: struct { 83 | Items []ServerAddresses `json:"items,omitempty"` 84 | }{Items: p.Addresses}, 85 | GTMVirtual_Server: struct { 86 | Items []VSrecord `json:"items,omitempty"` 87 | }{Items: p.GTMVirtual_Server}, 88 | }) 89 | } 90 | 91 | func (p *Server) UnmarshalJSON(b []byte) error { 92 | var dto serverDTO 93 | err := json.Unmarshal(b, &dto) 94 | if err != nil { 95 | return err 96 | } 97 | 98 | p.Name = dto.Name 99 | p.Datacenter = dto.Datacenter 100 | p.Monitor = dto.Monitor 101 | p.Virtual_server_discovery = dto.Virtual_server_discovery 102 | p.Product = dto.Product 103 | p.Addresses = dto.Addresses.Items 104 | p.GTMVirtual_Server = dto.GTMVirtual_Server.Items 105 | return nil 106 | } 107 | 108 | type ServerAddressess struct { 109 | Items []ServerAddresses `json:"items,omitempty"` 110 | } 111 | 112 | type ServerAddresses struct { 113 | Name string `json:"name"` 114 | Device_name string `json:"deviceName,omitempty"` 115 | Translation string `json:"translation,omitempty"` 116 | } 117 | 118 | type VSrecords struct { 119 | Items []VSrecord `json:"items,omitempty"` 120 | } 121 | 122 | type VSrecord struct { 123 | Name string `json:"name"` 124 | Destination string `json:"destination,omitempty"` 125 | } 126 | 127 | type Pool_as struct { 128 | Pool_as []Pool_a `json:"items"` 129 | } 130 | 131 | type Pool_a struct { 132 | Name string `json:"name,omitempty"` 133 | Monitor string `json:"monitor,omitempty"` 134 | Load_balancing_mode string `json:"load_balancing_mode,omitempty"` 135 | Max_answers_returned int `json:"max_answers_returned,omitempty"` 136 | Alternate_mode string `json:"alternate_mode,omitempty"` 137 | Fallback_ip string `json:"fallback_ip,omitempty"` 138 | Fallback_mode string `json:"fallback_mode,omitempty"` 139 | Members []string `json:"members,omitempty"` 140 | } 141 | 142 | const ( 143 | uriGtm = "gtm" 144 | uriServer = "server" 145 | uriDatacenter = "datacenter" 146 | uriGtmmonitor = "monitor" 147 | uriPool_a = "pool/a" 148 | ) 149 | 150 | func (b *BigIP) Datacenters() (*Datacenter, error) { 151 | var datacenter Datacenter 152 | err, _ := b.getForEntity(&datacenter, uriGtm, uriDatacenter) 153 | 154 | if err != nil { 155 | return nil, err 156 | } 157 | 158 | return &datacenter, nil 159 | } 160 | 161 | func (b *BigIP) CreateDatacenter(name, description, contact, app_service string, enabled, disabled bool, prober_pool string) error { 162 | config := &Datacenter{ 163 | Name: name, 164 | Description: description, 165 | Contact: contact, 166 | App_service: app_service, 167 | Enabled: enabled, 168 | Disabled: disabled, 169 | Prober_pool: prober_pool, 170 | } 171 | return b.post(config, uriGtm, uriDatacenter) 172 | } 173 | 174 | func (b *BigIP) ModifyDatacenter(*Datacenter) error { 175 | return b.patch(uriGtm, uriDatacenter) 176 | } 177 | 178 | func (b *BigIP) DeleteDatacenter(name string) error { 179 | return b.delete(uriGtm, uriDatacenter, name) 180 | } 181 | 182 | func (b *BigIP) Gtmmonitors() (*Gtmmonitor, error) { 183 | var gtmmonitor Gtmmonitor 184 | err, _ := b.getForEntity(>mmonitor, uriGtm, uriGtmmonitor, uriHttp) 185 | 186 | if err != nil { 187 | return nil, err 188 | } 189 | 190 | return >mmonitor, nil 191 | } 192 | func (b *BigIP) CreateGtmmonitor(name, defaults_from string, interval, probeTimeout int, recv, send string) error { 193 | config := &Gtmmonitor{ 194 | Name: name, 195 | Defaults_from: defaults_from, 196 | Interval: interval, 197 | Probe_timeout: probeTimeout, 198 | Recv: recv, 199 | Send: send, 200 | } 201 | return b.post(config, uriGtm, uriGtmmonitor, uriHttp) 202 | } 203 | 204 | func (b *BigIP) ModifyGtmmonitor(*Gtmmonitor) error { 205 | return b.patch(uriGtm, uriGtmmonitor, uriHttp) 206 | } 207 | 208 | func (b *BigIP) DeleteGtmmonitor(name string) error { 209 | return b.delete(uriGtm, uriGtmmonitor, uriHttp, name) 210 | } 211 | 212 | func (b *BigIP) CreateGtmserver(p *Server) error { 213 | log.Println(" what is the complete payload ", p) 214 | return b.post(p, uriGtm, uriServer) 215 | } 216 | 217 | // Update an existing policy. 218 | func (b *BigIP) UpdateGtmserver(name string, p *Server) error { 219 | return b.put(p, uriGtm, uriServer, name) 220 | } 221 | 222 | // Delete a policy by name. 223 | func (b *BigIP) DeleteGtmserver(name string) error { 224 | return b.delete(uriGtm, uriServer, name) 225 | } 226 | 227 | func (b *BigIP) GetGtmserver(name string) (*Server, error) { 228 | var p Server 229 | err, ok := b.getForEntity(&p, uriGtm, uriServer, name) 230 | if err != nil { 231 | return nil, err 232 | } 233 | if !ok { 234 | return nil, nil 235 | } 236 | 237 | return &p, nil 238 | } 239 | 240 | func (b *BigIP) CreatePool_a(name, monitor, load_balancing_mode string, max_answers_returned int, alternate_mode, fallback_ip, fallback_mode string, members []string) error { 241 | config := &Pool_a{ 242 | Name: name, 243 | Monitor: monitor, 244 | Load_balancing_mode: load_balancing_mode, 245 | Max_answers_returned: max_answers_returned, 246 | Alternate_mode: alternate_mode, 247 | Fallback_ip: fallback_ip, 248 | Fallback_mode: fallback_mode, 249 | Members: members, 250 | } 251 | log.Println("in poola now", config) 252 | return b.patch(config, uriGtm, uriPool_a) 253 | } 254 | 255 | func (b *BigIP) ModifyPool_a(config *Pool_a) error { 256 | return b.put(config, uriGtm, uriPool_a) 257 | } 258 | 259 | func (b *BigIP) Pool_as() (*Pool_a, error) { 260 | var pool_a Pool_a 261 | err, _ := b.getForEntity(&pool_a, uriGtm, uriPool_a) 262 | 263 | if err != nil { 264 | return nil, err 265 | } 266 | 267 | return &pool_a, nil 268 | } 269 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | Package spew implements a deep pretty printer for Go data structures to aid in 19 | debugging. 20 | 21 | A quick overview of the additional features spew provides over the built-in 22 | printing facilities for Go data types are as follows: 23 | 24 | * Pointers are dereferenced and followed 25 | * Circular data structures are detected and handled properly 26 | * Custom Stringer/error interfaces are optionally invoked, including 27 | on unexported types 28 | * Custom types which only implement the Stringer/error interfaces via 29 | a pointer receiver are optionally invoked when passing non-pointer 30 | variables 31 | * Byte arrays and slices are dumped like the hexdump -C command which 32 | includes offsets, byte values in hex, and ASCII output (only when using 33 | Dump style) 34 | 35 | There are two different approaches spew allows for dumping Go data structures: 36 | 37 | * Dump style which prints with newlines, customizable indentation, 38 | and additional debug information such as types and all pointer addresses 39 | used to indirect to the final value 40 | * A custom Formatter interface that integrates cleanly with the standard fmt 41 | package and replaces %v, %+v, %#v, and %#+v to provide inline printing 42 | similar to the default %v while providing the additional functionality 43 | outlined above and passing unsupported format verbs such as %x and %q 44 | along to fmt 45 | 46 | Quick Start 47 | 48 | This section demonstrates how to quickly get started with spew. See the 49 | sections below for further details on formatting and configuration options. 50 | 51 | To dump a variable with full newlines, indentation, type, and pointer 52 | information use Dump, Fdump, or Sdump: 53 | spew.Dump(myVar1, myVar2, ...) 54 | spew.Fdump(someWriter, myVar1, myVar2, ...) 55 | str := spew.Sdump(myVar1, myVar2, ...) 56 | 57 | Alternatively, if you would prefer to use format strings with a compacted inline 58 | printing style, use the convenience wrappers Printf, Fprintf, etc with 59 | %v (most compact), %+v (adds pointer addresses), %#v (adds types), or 60 | %#+v (adds types and pointer addresses): 61 | spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) 62 | spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 63 | spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) 64 | spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 65 | 66 | Configuration Options 67 | 68 | Configuration of spew is handled by fields in the ConfigState type. For 69 | convenience, all of the top-level functions use a global state available 70 | via the spew.Config global. 71 | 72 | It is also possible to create a ConfigState instance that provides methods 73 | equivalent to the top-level functions. This allows concurrent configuration 74 | options. See the ConfigState documentation for more details. 75 | 76 | The following configuration options are available: 77 | * Indent 78 | String to use for each indentation level for Dump functions. 79 | It is a single space by default. A popular alternative is "\t". 80 | 81 | * MaxDepth 82 | Maximum number of levels to descend into nested data structures. 83 | There is no limit by default. 84 | 85 | * DisableMethods 86 | Disables invocation of error and Stringer interface methods. 87 | Method invocation is enabled by default. 88 | 89 | * DisablePointerMethods 90 | Disables invocation of error and Stringer interface methods on types 91 | which only accept pointer receivers from non-pointer variables. 92 | Pointer method invocation is enabled by default. 93 | 94 | * DisablePointerAddresses 95 | DisablePointerAddresses specifies whether to disable the printing of 96 | pointer addresses. This is useful when diffing data structures in tests. 97 | 98 | * DisableCapacities 99 | DisableCapacities specifies whether to disable the printing of 100 | capacities for arrays, slices, maps and channels. This is useful when 101 | diffing data structures in tests. 102 | 103 | * ContinueOnMethod 104 | Enables recursion into types after invoking error and Stringer interface 105 | methods. Recursion after method invocation is disabled by default. 106 | 107 | * SortKeys 108 | Specifies map keys should be sorted before being printed. Use 109 | this to have a more deterministic, diffable output. Note that 110 | only native types (bool, int, uint, floats, uintptr and string) 111 | and types which implement error or Stringer interfaces are 112 | supported with other types sorted according to the 113 | reflect.Value.String() output which guarantees display 114 | stability. Natural map order is used by default. 115 | 116 | * SpewKeys 117 | Specifies that, as a last resort attempt, map keys should be 118 | spewed to strings and sorted by those strings. This is only 119 | considered if SortKeys is true. 120 | 121 | Dump Usage 122 | 123 | Simply call spew.Dump with a list of variables you want to dump: 124 | 125 | spew.Dump(myVar1, myVar2, ...) 126 | 127 | You may also call spew.Fdump if you would prefer to output to an arbitrary 128 | io.Writer. For example, to dump to standard error: 129 | 130 | spew.Fdump(os.Stderr, myVar1, myVar2, ...) 131 | 132 | A third option is to call spew.Sdump to get the formatted output as a string: 133 | 134 | str := spew.Sdump(myVar1, myVar2, ...) 135 | 136 | Sample Dump Output 137 | 138 | See the Dump example for details on the setup of the types and variables being 139 | shown here. 140 | 141 | (main.Foo) { 142 | unexportedField: (*main.Bar)(0xf84002e210)({ 143 | flag: (main.Flag) flagTwo, 144 | data: (uintptr) 145 | }), 146 | ExportedField: (map[interface {}]interface {}) (len=1) { 147 | (string) (len=3) "one": (bool) true 148 | } 149 | } 150 | 151 | Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C 152 | command as shown. 153 | ([]uint8) (len=32 cap=32) { 154 | 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | 155 | 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| 156 | 00000020 31 32 |12| 157 | } 158 | 159 | Custom Formatter 160 | 161 | Spew provides a custom formatter that implements the fmt.Formatter interface 162 | so that it integrates cleanly with standard fmt package printing functions. The 163 | formatter is useful for inline printing of smaller data types similar to the 164 | standard %v format specifier. 165 | 166 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 167 | addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb 168 | combinations. Any other verbs such as %x and %q will be sent to the the 169 | standard fmt package for formatting. In addition, the custom formatter ignores 170 | the width and precision arguments (however they will still work on the format 171 | specifiers not handled by the custom formatter). 172 | 173 | Custom Formatter Usage 174 | 175 | The simplest way to make use of the spew custom formatter is to call one of the 176 | convenience functions such as spew.Printf, spew.Println, or spew.Printf. The 177 | functions have syntax you are most likely already familiar with: 178 | 179 | spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) 180 | spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 181 | spew.Println(myVar, myVar2) 182 | spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) 183 | spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 184 | 185 | See the Index for the full list convenience functions. 186 | 187 | Sample Formatter Output 188 | 189 | Double pointer to a uint8: 190 | %v: <**>5 191 | %+v: <**>(0xf8400420d0->0xf8400420c8)5 192 | %#v: (**uint8)5 193 | %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 194 | 195 | Pointer to circular struct with a uint8 field and a pointer to itself: 196 | %v: <*>{1 <*>} 197 | %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} 198 | %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} 199 | %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} 200 | 201 | See the Printf example for details on the setup of variables being shown 202 | here. 203 | 204 | Errors 205 | 206 | Since it is possible for custom Stringer/error interfaces to panic, spew 207 | detects them and handles them internally by printing the panic information 208 | inline with the output. Since spew is intended to provide deep pretty printing 209 | capabilities on structures, it intentionally does not return any errors. 210 | */ 211 | package spew 212 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "io" 23 | "reflect" 24 | "sort" 25 | "strconv" 26 | ) 27 | 28 | // Some constants in the form of bytes to avoid string overhead. This mirrors 29 | // the technique used in the fmt package. 30 | var ( 31 | panicBytes = []byte("(PANIC=") 32 | plusBytes = []byte("+") 33 | iBytes = []byte("i") 34 | trueBytes = []byte("true") 35 | falseBytes = []byte("false") 36 | interfaceBytes = []byte("(interface {})") 37 | commaNewlineBytes = []byte(",\n") 38 | newlineBytes = []byte("\n") 39 | openBraceBytes = []byte("{") 40 | openBraceNewlineBytes = []byte("{\n") 41 | closeBraceBytes = []byte("}") 42 | asteriskBytes = []byte("*") 43 | colonBytes = []byte(":") 44 | colonSpaceBytes = []byte(": ") 45 | openParenBytes = []byte("(") 46 | closeParenBytes = []byte(")") 47 | spaceBytes = []byte(" ") 48 | pointerChainBytes = []byte("->") 49 | nilAngleBytes = []byte("") 50 | maxNewlineBytes = []byte("\n") 51 | maxShortBytes = []byte("") 52 | circularBytes = []byte("") 53 | circularShortBytes = []byte("") 54 | invalidAngleBytes = []byte("") 55 | openBracketBytes = []byte("[") 56 | closeBracketBytes = []byte("]") 57 | percentBytes = []byte("%") 58 | precisionBytes = []byte(".") 59 | openAngleBytes = []byte("<") 60 | closeAngleBytes = []byte(">") 61 | openMapBytes = []byte("map[") 62 | closeMapBytes = []byte("]") 63 | lenEqualsBytes = []byte("len=") 64 | capEqualsBytes = []byte("cap=") 65 | ) 66 | 67 | // hexDigits is used to map a decimal value to a hex digit. 68 | var hexDigits = "0123456789abcdef" 69 | 70 | // catchPanic handles any panics that might occur during the handleMethods 71 | // calls. 72 | func catchPanic(w io.Writer, v reflect.Value) { 73 | if err := recover(); err != nil { 74 | w.Write(panicBytes) 75 | fmt.Fprintf(w, "%v", err) 76 | w.Write(closeParenBytes) 77 | } 78 | } 79 | 80 | // handleMethods attempts to call the Error and String methods on the underlying 81 | // type the passed reflect.Value represents and outputes the result to Writer w. 82 | // 83 | // It handles panics in any called methods by catching and displaying the error 84 | // as the formatted value. 85 | func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { 86 | // We need an interface to check if the type implements the error or 87 | // Stringer interface. However, the reflect package won't give us an 88 | // interface on certain things like unexported struct fields in order 89 | // to enforce visibility rules. We use unsafe, when it's available, 90 | // to bypass these restrictions since this package does not mutate the 91 | // values. 92 | if !v.CanInterface() { 93 | if UnsafeDisabled { 94 | return false 95 | } 96 | 97 | v = unsafeReflectValue(v) 98 | } 99 | 100 | // Choose whether or not to do error and Stringer interface lookups against 101 | // the base type or a pointer to the base type depending on settings. 102 | // Technically calling one of these methods with a pointer receiver can 103 | // mutate the value, however, types which choose to satisify an error or 104 | // Stringer interface with a pointer receiver should not be mutating their 105 | // state inside these interface methods. 106 | if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { 107 | v = unsafeReflectValue(v) 108 | } 109 | if v.CanAddr() { 110 | v = v.Addr() 111 | } 112 | 113 | // Is it an error or Stringer? 114 | switch iface := v.Interface().(type) { 115 | case error: 116 | defer catchPanic(w, v) 117 | if cs.ContinueOnMethod { 118 | w.Write(openParenBytes) 119 | w.Write([]byte(iface.Error())) 120 | w.Write(closeParenBytes) 121 | w.Write(spaceBytes) 122 | return false 123 | } 124 | 125 | w.Write([]byte(iface.Error())) 126 | return true 127 | 128 | case fmt.Stringer: 129 | defer catchPanic(w, v) 130 | if cs.ContinueOnMethod { 131 | w.Write(openParenBytes) 132 | w.Write([]byte(iface.String())) 133 | w.Write(closeParenBytes) 134 | w.Write(spaceBytes) 135 | return false 136 | } 137 | w.Write([]byte(iface.String())) 138 | return true 139 | } 140 | return false 141 | } 142 | 143 | // printBool outputs a boolean value as true or false to Writer w. 144 | func printBool(w io.Writer, val bool) { 145 | if val { 146 | w.Write(trueBytes) 147 | } else { 148 | w.Write(falseBytes) 149 | } 150 | } 151 | 152 | // printInt outputs a signed integer value to Writer w. 153 | func printInt(w io.Writer, val int64, base int) { 154 | w.Write([]byte(strconv.FormatInt(val, base))) 155 | } 156 | 157 | // printUint outputs an unsigned integer value to Writer w. 158 | func printUint(w io.Writer, val uint64, base int) { 159 | w.Write([]byte(strconv.FormatUint(val, base))) 160 | } 161 | 162 | // printFloat outputs a floating point value using the specified precision, 163 | // which is expected to be 32 or 64bit, to Writer w. 164 | func printFloat(w io.Writer, val float64, precision int) { 165 | w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) 166 | } 167 | 168 | // printComplex outputs a complex value using the specified float precision 169 | // for the real and imaginary parts to Writer w. 170 | func printComplex(w io.Writer, c complex128, floatPrecision int) { 171 | r := real(c) 172 | w.Write(openParenBytes) 173 | w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) 174 | i := imag(c) 175 | if i >= 0 { 176 | w.Write(plusBytes) 177 | } 178 | w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) 179 | w.Write(iBytes) 180 | w.Write(closeParenBytes) 181 | } 182 | 183 | // printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' 184 | // prefix to Writer w. 185 | func printHexPtr(w io.Writer, p uintptr) { 186 | // Null pointer. 187 | num := uint64(p) 188 | if num == 0 { 189 | w.Write(nilAngleBytes) 190 | return 191 | } 192 | 193 | // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix 194 | buf := make([]byte, 18) 195 | 196 | // It's simpler to construct the hex string right to left. 197 | base := uint64(16) 198 | i := len(buf) - 1 199 | for num >= base { 200 | buf[i] = hexDigits[num%base] 201 | num /= base 202 | i-- 203 | } 204 | buf[i] = hexDigits[num] 205 | 206 | // Add '0x' prefix. 207 | i-- 208 | buf[i] = 'x' 209 | i-- 210 | buf[i] = '0' 211 | 212 | // Strip unused leading bytes. 213 | buf = buf[i:] 214 | w.Write(buf) 215 | } 216 | 217 | // valuesSorter implements sort.Interface to allow a slice of reflect.Value 218 | // elements to be sorted. 219 | type valuesSorter struct { 220 | values []reflect.Value 221 | strings []string // either nil or same len and values 222 | cs *ConfigState 223 | } 224 | 225 | // newValuesSorter initializes a valuesSorter instance, which holds a set of 226 | // surrogate keys on which the data should be sorted. It uses flags in 227 | // ConfigState to decide if and how to populate those surrogate keys. 228 | func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { 229 | vs := &valuesSorter{values: values, cs: cs} 230 | if canSortSimply(vs.values[0].Kind()) { 231 | return vs 232 | } 233 | if !cs.DisableMethods { 234 | vs.strings = make([]string, len(values)) 235 | for i := range vs.values { 236 | b := bytes.Buffer{} 237 | if !handleMethods(cs, &b, vs.values[i]) { 238 | vs.strings = nil 239 | break 240 | } 241 | vs.strings[i] = b.String() 242 | } 243 | } 244 | if vs.strings == nil && cs.SpewKeys { 245 | vs.strings = make([]string, len(values)) 246 | for i := range vs.values { 247 | vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) 248 | } 249 | } 250 | return vs 251 | } 252 | 253 | // canSortSimply tests whether a reflect.Kind is a primitive that can be sorted 254 | // directly, or whether it should be considered for sorting by surrogate keys 255 | // (if the ConfigState allows it). 256 | func canSortSimply(kind reflect.Kind) bool { 257 | // This switch parallels valueSortLess, except for the default case. 258 | switch kind { 259 | case reflect.Bool: 260 | return true 261 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 262 | return true 263 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 264 | return true 265 | case reflect.Float32, reflect.Float64: 266 | return true 267 | case reflect.String: 268 | return true 269 | case reflect.Uintptr: 270 | return true 271 | case reflect.Array: 272 | return true 273 | } 274 | return false 275 | } 276 | 277 | // Len returns the number of values in the slice. It is part of the 278 | // sort.Interface implementation. 279 | func (s *valuesSorter) Len() int { 280 | return len(s.values) 281 | } 282 | 283 | // Swap swaps the values at the passed indices. It is part of the 284 | // sort.Interface implementation. 285 | func (s *valuesSorter) Swap(i, j int) { 286 | s.values[i], s.values[j] = s.values[j], s.values[i] 287 | if s.strings != nil { 288 | s.strings[i], s.strings[j] = s.strings[j], s.strings[i] 289 | } 290 | } 291 | 292 | // valueSortLess returns whether the first value should sort before the second 293 | // value. It is used by valueSorter.Less as part of the sort.Interface 294 | // implementation. 295 | func valueSortLess(a, b reflect.Value) bool { 296 | switch a.Kind() { 297 | case reflect.Bool: 298 | return !a.Bool() && b.Bool() 299 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 300 | return a.Int() < b.Int() 301 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 302 | return a.Uint() < b.Uint() 303 | case reflect.Float32, reflect.Float64: 304 | return a.Float() < b.Float() 305 | case reflect.String: 306 | return a.String() < b.String() 307 | case reflect.Uintptr: 308 | return a.Uint() < b.Uint() 309 | case reflect.Array: 310 | // Compare the contents of both arrays. 311 | l := a.Len() 312 | for i := 0; i < l; i++ { 313 | av := a.Index(i) 314 | bv := b.Index(i) 315 | if av.Interface() == bv.Interface() { 316 | continue 317 | } 318 | return valueSortLess(av, bv) 319 | } 320 | } 321 | return a.String() < b.String() 322 | } 323 | 324 | // Less returns whether the value at index i should sort before the 325 | // value at index j. It is part of the sort.Interface implementation. 326 | func (s *valuesSorter) Less(i, j int) bool { 327 | if s.strings == nil { 328 | return valueSortLess(s.values[i], s.values[j]) 329 | } 330 | return s.strings[i] < s.strings[j] 331 | } 332 | 333 | // sortValues is a sort function that handles both native types and any type that 334 | // can be converted to error or Stringer. Other inputs are sorted according to 335 | // their Value.String() value to ensure display stability. 336 | func sortValues(values []reflect.Value, cs *ConfigState) { 337 | if len(values) == 0 { 338 | return 339 | } 340 | sort.Sort(newValuesSorter(values, cs)) 341 | } 342 | -------------------------------------------------------------------------------- /f5teem/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /examples/asm/test_asm.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/f5devcentral/go-bigip" 8 | ) 9 | 10 | // testDosProfile tests CRUD operations for DOS profiles 11 | func testDosProfile(f5 *bigip.BigIP) { 12 | fmt.Println("\n=== Testing DOS Profile CRUD Operations ===") 13 | 14 | // Test profile configuration 15 | dosProfile := &bigip.DOSProfile{ 16 | Name: "test-dos-profile", 17 | ThresholdSensitivity: "medium", 18 | } 19 | 20 | // CREATE: Add DOS profile 21 | fmt.Println("Creating DOS profile...") 22 | err := f5.AddDOSProfile(dosProfile) 23 | if err != nil { 24 | log.Printf("Error creating DOS profile: %v", err) 25 | return 26 | } 27 | fmt.Println("DOS profile created successfully") 28 | 29 | // READ: Get all DOS profiles 30 | fmt.Println("Getting all DOS profiles...") 31 | profiles, err := f5.DOSProfiles() 32 | if err != nil { 33 | log.Printf("Error getting DOS profiles: %v", err) 34 | return 35 | } 36 | fmt.Printf("Found %d DOS profiles\n", len(profiles.DOSProfiles)) 37 | 38 | // READ: Get specific DOS profile 39 | fmt.Println("Getting specific DOS profile...") 40 | profile, err := f5.GetDOSProfile("test-dos-profile") 41 | if err != nil { 42 | log.Printf("Error getting DOS profile: %v", err) 43 | return 44 | } 45 | if profile != nil { 46 | fmt.Printf("Retrieved DOS profile: %s with sensitivity: %s\n", profile.Name, profile.ThresholdSensitivity) 47 | } 48 | 49 | // UPDATE: Modify DOS profile 50 | fmt.Println("Updating DOS profile...") 51 | dosProfile.ThresholdSensitivity = "high" 52 | err = f5.ModifyDOSProfile("test-dos-profile", dosProfile) 53 | if err != nil { 54 | log.Printf("Error updating DOS profile: %v", err) 55 | return 56 | } 57 | fmt.Println("DOS profile updated successfully") 58 | 59 | // Verify update 60 | updatedProfile, err := f5.GetDOSProfile("test-dos-profile") 61 | if err != nil { 62 | log.Printf("Error getting updated DOS profile: %v", err) 63 | return 64 | } 65 | if updatedProfile != nil { 66 | fmt.Printf("Updated DOS profile sensitivity: %s\n", updatedProfile.ThresholdSensitivity) 67 | } 68 | 69 | // DELETE: Remove DOS profile 70 | fmt.Println("Deleting DOS profile...") 71 | err = f5.DeleteDOSProfile("test-dos-profile") 72 | if err != nil { 73 | log.Printf("Error deleting DOS profile: %v", err) 74 | return 75 | } 76 | fmt.Println("DOS profile deleted successfully") 77 | 78 | // Verify deletion 79 | _, err = f5.GetDOSProfile("test-dos-profile") 80 | if err != nil && err.Error() == "01020036:3: The requested DOS profile (/Common/test-dos-profile) was not found." { 81 | fmt.Println("DOS profile deletion confirmed") 82 | return 83 | } 84 | } 85 | 86 | // testFirewallPolicy tests CRUD operations for Firewall policies 87 | func testFirewallPolicy(f5 *bigip.BigIP) { 88 | fmt.Println("\n=== Testing Firewall Policy CRUD Operations ===") 89 | 90 | // Test policy configuration 91 | firewallPolicy := &bigip.FirewallPolicy{ 92 | Name: "test-firewall-policy", 93 | } 94 | 95 | // CREATE: Add Firewall policy 96 | fmt.Println("Creating Firewall policy...") 97 | err := f5.AddFirewallPolicy(firewallPolicy) 98 | if err != nil { 99 | log.Printf("Error creating Firewall policy: %v", err) 100 | return 101 | } 102 | fmt.Println("Firewall policy created successfully") 103 | 104 | // READ: Get all Firewall policies 105 | fmt.Println("Getting all Firewall policies...") 106 | policies, err := f5.FirewallPolicies() 107 | if err != nil { 108 | log.Printf("Error getting Firewall policies: %v", err) 109 | return 110 | } 111 | fmt.Printf("Found %d Firewall policies\n", len(policies.FirewallPolicies)) 112 | 113 | // READ: Get specific Firewall policy 114 | fmt.Println("Getting specific Firewall policy...") 115 | policy, err := f5.GetFirewallPolicy("test-firewall-policy") 116 | if err != nil { 117 | log.Printf("Error getting Firewall policy: %v", err) 118 | return 119 | } 120 | if policy != nil { 121 | fmt.Printf("Retrieved Firewall policy: %s\n", policy.Name) 122 | } 123 | 124 | //// UPDATE: Modify Firewall policy 125 | //fmt.Println("Updating Firewall policy...") 126 | //// Note: For firewall policies, we mainly update metadata fields 127 | //err = f5.ModifyFirewallPolicy("test-firewall-policy", firewallPolicy) 128 | //if err != nil { 129 | // log.Printf("Error updating Firewall policy: %v", err) 130 | // return 131 | //} 132 | //fmt.Println("Firewall policy updated successfully") 133 | 134 | // DELETE: Remove Firewall policy 135 | fmt.Println("Deleting Firewall policy...") 136 | err = f5.DeleteFirewallPolicy("test-firewall-policy") 137 | if err != nil { 138 | log.Printf("Error deleting Firewall policy: %v", err) 139 | return 140 | } 141 | fmt.Println("Firewall policy deleted successfully") 142 | 143 | // Verify deletion 144 | _, err = f5.GetFirewallPolicy("test-firewall-policy") 145 | if err != nil { 146 | if err.Error() == "01020036:3: The requested firewall policy (/Common/test-firewall-policy) was not found." { 147 | fmt.Println("Firewall policy deletion confirmed") 148 | } 149 | return 150 | } 151 | } 152 | 153 | // testIpIntelligence tests CRUD operations for IP Intelligence policies 154 | func testIpIntelligence(f5 *bigip.BigIP) { 155 | fmt.Println("\n=== Testing IP Intelligence Policy CRUD Operations ===") 156 | 157 | // Test policy configuration 158 | ipIntelPolicy := &bigip.IPIntelligencePolicy{ 159 | Name: "test-ip-intelligence-policy", 160 | DefaultAction: "drop", 161 | DefaultLogBlacklistHitOnly: "no", 162 | DefaultLogBlacklistWhitelistHit: "no", 163 | } 164 | 165 | // CREATE: Add IP Intelligence policy 166 | fmt.Println("Creating IP Intelligence policy...") 167 | err := f5.AddIPIntelligencePolicy(ipIntelPolicy) 168 | if err != nil { 169 | log.Printf("Error creating IP Intelligence policy: %v", err) 170 | return 171 | } 172 | fmt.Println("IP Intelligence policy created successfully") 173 | 174 | // READ: Get all IP Intelligence policies 175 | fmt.Println("Getting all IP Intelligence policies...") 176 | policies, err := f5.IPIntelligencePolicies() 177 | if err != nil { 178 | log.Printf("Error getting IP Intelligence policies: %v", err) 179 | return 180 | } 181 | fmt.Printf("Found %d IP Intelligence policies\n", len(policies.IPIntelligencePolicies)) 182 | 183 | // READ: Get specific IP Intelligence policy 184 | fmt.Println("Getting specific IP Intelligence policy...") 185 | policy, err := f5.GetIPIntelligencePolicy("test-ip-intelligence-policy") 186 | if err != nil { 187 | log.Printf("Error getting IP Intelligence policy: %v", err) 188 | return 189 | } 190 | if policy != nil { 191 | fmt.Printf("Retrieved IP Intelligence policy: %s with default action: %s\n", policy.Name, policy.DefaultAction) 192 | } 193 | 194 | // UPDATE: Modify IP Intelligence policy 195 | fmt.Println("Updating IP Intelligence policy...") 196 | ipIntelPolicy.DefaultAction = "accept" 197 | ipIntelPolicy.DefaultLogBlacklistHitOnly = "yes" 198 | err = f5.ModifyIPIntelligencePolicy("test-ip-intelligence-policy", ipIntelPolicy) 199 | if err != nil { 200 | log.Printf("Error updating IP Intelligence policy: %v", err) 201 | return 202 | } 203 | fmt.Println("IP Intelligence policy updated successfully") 204 | 205 | // Verify update 206 | updatedPolicy, err := f5.GetIPIntelligencePolicy("test-ip-intelligence-policy") 207 | if err != nil { 208 | log.Printf("Error getting updated IP Intelligence policy: %v", err) 209 | return 210 | } 211 | if updatedPolicy.DefaultLogBlacklistHitOnly == "yes" && ipIntelPolicy.DefaultAction == "accept" { 212 | fmt.Printf("Updated IP Intelligence policy default action: %s\n", updatedPolicy.DefaultAction) 213 | } 214 | 215 | // DELETE: Remove IP Intelligence policy 216 | fmt.Println("Deleting IP Intelligence policy...") 217 | err = f5.DeleteIPIntelligencePolicy("test-ip-intelligence-policy") 218 | if err != nil { 219 | log.Printf("Error deleting IP Intelligence policy: %v", err) 220 | return 221 | } 222 | fmt.Println("IP Intelligence policy deleted successfully") 223 | 224 | // Verify deletion 225 | _, err = f5.GetIPIntelligencePolicy("test-ip-intelligence-policy") 226 | if err != nil { 227 | if err.Error() == "01020036:3: The requested Firewall dynamic black/white lists policy (/Common/test-ip-intelligence-policy) was not found." { 228 | fmt.Println("IP Intelligence policy deletion confirmed") 229 | } 230 | } 231 | } 232 | 233 | // testLogProfile tests CRUD operations for Security Log profiles 234 | func testLogProfile(f5 *bigip.BigIP) { 235 | fmt.Println("\n=== Testing Security Log Profile CRUD Operations ===") 236 | 237 | // Test profile configuration - using updated structure with correct JSON tags 238 | logProfile := &bigip.SecurityLogProfile{ 239 | Name: "test-security-log-profile", 240 | Description: "Test security log profile for demonstration", 241 | IPIntelligence: struct { 242 | AggregateRate int `json:"aggregate-rate,omitempty"` 243 | LogGeo string `json:"log-geo,omitempty"` 244 | LogRtbh string `json:"log-rtbh,omitempty"` 245 | LogScrubber string `json:"log-scrubber,omitempty"` 246 | LogShun string `json:"log-shun,omitempty"` 247 | LogTranslationFields string `json:"log-translation-fields,omitempty"` 248 | }{ 249 | AggregateRate: 100, 250 | LogGeo: "disabled", 251 | LogRtbh: "disabled", 252 | LogScrubber: "disabled", 253 | LogShun: "disabled", 254 | LogTranslationFields: "enabled", 255 | }, 256 | } 257 | 258 | // CREATE: Add Security Log profile 259 | fmt.Println("Creating Security Log profile...") 260 | err := f5.AddSecurityLogProfile(logProfile) 261 | if err != nil { 262 | log.Printf("Error creating Security Log profile: %v", err) 263 | return 264 | } 265 | fmt.Println("Security Log profile created successfully") 266 | 267 | // READ: Get all Security Log profiles 268 | fmt.Println("Getting all Security Log profiles...") 269 | profiles, err := f5.SecurityLogProfiles() 270 | if err != nil { 271 | log.Printf("Error getting Security Log profiles: %v", err) 272 | return 273 | } 274 | fmt.Printf("Found %d Security Log profiles\n", len(profiles.SecurityLogProfiles)) 275 | 276 | // READ: Get specific Security Log profile 277 | fmt.Println("Getting specific Security Log profile...") 278 | profile, err := f5.GetSecurityLogProfile("test-security-log-profile") 279 | if err != nil { 280 | log.Printf("Error getting Security Log profile: %v", err) 281 | return 282 | } 283 | if profile != nil { 284 | fmt.Printf("Retrieved Security Log profile: %s with description: %s\n", profile.Name, profile.Description) 285 | } 286 | 287 | // UPDATE: Modify Security Log profile 288 | fmt.Println("Updating Security Log profile...") 289 | logProfile.Description = "Updated test security log profile" 290 | logProfile.IPIntelligence.AggregateRate = 200 291 | logProfile.IPIntelligence.LogGeo = "disabled" 292 | err = f5.ModifySecurityLogProfile("test-security-log-profile", logProfile) 293 | if err != nil { 294 | log.Printf("Error updating Security Log profile: %v", err) 295 | return 296 | } 297 | fmt.Println("Security Log profile updated successfully") 298 | 299 | // Verify update 300 | updatedProfile, err := f5.GetSecurityLogProfile("test-security-log-profile") 301 | if err != nil { 302 | log.Printf("Error getting updated Security Log profile: %v", err) 303 | return 304 | } 305 | if updatedProfile.IPIntelligence.AggregateRate == 200 { 306 | fmt.Printf("Updated aggregate rate: %d\n", updatedProfile.IPIntelligence.AggregateRate) 307 | } 308 | 309 | // DELETE: Remove Security Log profile 310 | fmt.Println("Deleting Security Log profile...") 311 | err = f5.DeleteSecurityLogProfile("test-security-log-profile") 312 | if err != nil { 313 | log.Printf("Error deleting Security Log profile: %v", err) 314 | return 315 | } 316 | fmt.Println("Security Log profile deleted successfully") 317 | 318 | // Verify deletion 319 | _, err = f5.GetSecurityLogProfile("test-security-log-profile") 320 | if err != nil { 321 | if err.Error() == "01020036:3: The requested Security Log profile (/Common/test-security-log-profile) was not found." { 322 | fmt.Println("Security Log profile deletion confirmed") 323 | 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /device.go: -------------------------------------------------------------------------------- 1 | /* 2 | Original work Copyright © 2015 Scott Ware 3 | Modifications Copyright 2019 F5 Networks Inc 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | You may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | */ 11 | package bigip 12 | 13 | import ( 14 | "encoding/json" 15 | ) 16 | 17 | // LIC contains device license for BIG-IP system. 18 | type LICs struct { 19 | LIC []LIC `json:"items"` 20 | } 21 | 22 | // VirtualAddress contains information about each individual virtual address. 23 | type LIC struct { 24 | DeviceAddress string 25 | Username string 26 | Password string 27 | } 28 | 29 | type LicensePools struct { 30 | LicensePool []LicensePool `json:"items"` 31 | } 32 | 33 | type LicensePool struct { 34 | Items []struct { 35 | Uuid string `json:"Uuid,omitempty"` 36 | } 37 | } 38 | 39 | type LICDTO struct { 40 | DeviceAddress string `json:"deviceAddress,omitempty"` 41 | Username string `json:"username,omitempty"` 42 | Password string `json:"password,omitempty"` 43 | } 44 | 45 | type Devicenames struct { 46 | Devicenames []Devicename `json:"items"` 47 | } 48 | 49 | type Devicename struct { 50 | Command string `json:"command,omitempty"` 51 | Name string `json:"name,omitempty"` 52 | Target string `json:"target,omitempty"` 53 | } 54 | 55 | type Devices struct { 56 | Devices []Device `json:"items"` 57 | } 58 | 59 | // UnicastAddress is an abstraction and used by Device 60 | type UnicastAddress struct { 61 | EffectiveIP string `json:"effectiveIp"` 62 | EffectivePort int `json:"effectivePort"` 63 | IP string `json:"ip"` 64 | Port int `json:"port"` 65 | } 66 | 67 | // Device represents an individual bigip as viewed from the cluster 68 | // see: https://devcentral.f5.com/Wiki/iControlREST.APIRef_tm_cm_device.ashx 69 | type Device struct { 70 | Name string `json:"name,omitempty"` 71 | MirrorIp string `json:"mirrorIp,omitempty"` 72 | MirrorSecondaryIp string `json:"mirrorSecondaryIp,omitempty"` 73 | ActiveModules []string `json:"activeModules,omitempty"` 74 | AppService string `json:"appService,omitempty"` 75 | BaseMac string `json:"baseMac,omitempty"` 76 | Build string `json:"build,omitempty"` 77 | Cert string `json:"cert,omitempty"` 78 | ChassisID string `json:"chassisId,omitempty"` 79 | ChassisType string `json:"chassisType,omitempty"` 80 | ConfigsyncIp string `json:"configsyncIp,omitempty"` 81 | Comment string `json:"comment,omitempty"` 82 | Contact string `json:"contact,omitempty"` 83 | Description string `json:"description,omitempty"` 84 | Edition string `json:"edition,omitempty"` 85 | FailoverState string `json:"failoverState,omitempty"` 86 | HaCapacity int `json:"haCapacity,omitempty"` 87 | Hostname string `json:"hostname,omitempty"` 88 | InactiveModules string `json:"inactiveModules,omitempty"` 89 | Key string `json:"key,omitempty"` 90 | Location string `json:"location,omitempty"` 91 | ManagementIP string `json:"managementIp,omitempty"` 92 | MarketingName string `json:"marketingName,omitempty"` 93 | MulticastInterface string `json:"multicastInterface,omitempty"` 94 | MulticastIP string `json:"multicastIp,omitempty"` 95 | MulticastPort int `json:"multicastPort,omitempty"` 96 | OptionalModules []string `json:"optionalModules,omitempty"` 97 | Partition string `json:"partition,omitempty"` 98 | PlatformID string `json:"platformId,omitempty"` 99 | Product string `json:"product,omitempty"` 100 | SelfDevice string `json:"selfDevice,omitempty"` 101 | TimeLimitedModules []string `json:"timeLimitedModules,omitempty"` 102 | TimeZone string `json:"timeZone,omitempty"` 103 | Version string `json:"version,omitempty"` 104 | UnicastAddress []UnicastAddress 105 | } 106 | 107 | type Devicegroups struct { 108 | Devicegroups []Devicegroup `json:"items"` 109 | } 110 | 111 | type Devicegroup struct { 112 | AutoSync string 113 | Name string 114 | Partition string 115 | Description string 116 | Type string 117 | FullLoadOnSync string 118 | SaveOnAutoSync string 119 | NetworkFailover string 120 | IncrementalConfigSyncSizeMax int 121 | Deviceb []Devicerecord 122 | } 123 | type devicegroupDTO struct { 124 | AutoSync string `json:"autoSync,omitempty"` 125 | Name string `json:"name,omitempty"` 126 | Partition string `json:"partition,omitempty"` 127 | Description string `json:"description,omitempty"` 128 | Type string `json:"type,omitempty"` 129 | FullLoadOnSync string `json:"fullLoadOnSync,omitempty"` 130 | SaveOnAutoSync string `json:"saveOnAutoSync,omitempty"` 131 | NetworkFailover string `json:"networkFailover,omitempty"` 132 | IncrementalConfigSyncSizeMax int `json:"incrementalConfigSyncSizeMax,omitempty"` 133 | Deviceb struct { 134 | Items []Devicerecord `json:"items,omitempty"` 135 | } `json:"devicesReference,omitempty"` 136 | } 137 | 138 | type Devicerecords struct { 139 | Items []Devicerecord `json:"items,omitempty"` 140 | } 141 | 142 | type Devicerecord struct { 143 | SetSyncLeader bool `json:"setSyncLeader"` 144 | Name string `json:"name"` 145 | } 146 | 147 | func (p *Devicegroup) MarshalJSON() ([]byte, error) { 148 | return json.Marshal(devicegroupDTO{ 149 | Name: p.Name, 150 | Partition: p.Partition, 151 | AutoSync: p.AutoSync, 152 | Description: p.Description, 153 | Type: p.Type, 154 | FullLoadOnSync: p.FullLoadOnSync, 155 | SaveOnAutoSync: p.SaveOnAutoSync, 156 | NetworkFailover: p.NetworkFailover, 157 | IncrementalConfigSyncSizeMax: p.IncrementalConfigSyncSizeMax, 158 | Deviceb: struct { 159 | Items []Devicerecord `json:"items,omitempty"` 160 | }{Items: p.Deviceb}, 161 | }) 162 | } 163 | 164 | func (p *Devicegroup) UnmarshalJSON(b []byte) error { 165 | var dto devicegroupDTO 166 | err := json.Unmarshal(b, &dto) 167 | if err != nil { 168 | return err 169 | } 170 | 171 | p.Name = dto.Name 172 | p.Partition = dto.Partition 173 | p.AutoSync = dto.AutoSync 174 | p.Description = dto.Description 175 | p.Type = dto.Type 176 | p.FullLoadOnSync = dto.FullLoadOnSync 177 | p.SaveOnAutoSync = dto.SaveOnAutoSync 178 | p.NetworkFailover = dto.NetworkFailover 179 | p.IncrementalConfigSyncSizeMax = dto.IncrementalConfigSyncSizeMax 180 | p.Deviceb = dto.Deviceb.Items 181 | 182 | return nil 183 | } 184 | 185 | // https://10.192.74.80/mgmt/cm/device/licensing/pool/purchased-pool/licenses 186 | // The above command will spit out license uuid and which should be mapped uriUuid 187 | const ( 188 | uriMgmt = "mgmt" 189 | uriCm = "cm" 190 | uriDiv = "device" 191 | uriDevices = "devices" 192 | uriDG = "device-group" 193 | uriLins = "licensing" 194 | uriPoo = "pool" 195 | uriPur = "purchased-pool" 196 | uriLicn = "licenses" 197 | uriMemb = "members" 198 | uriUtility = "utility" 199 | uriOfferings = "offerings" 200 | uriF5BIGMSPBT10G = "f37c66e0-a80d-43e8-924b-3bbe9fe96bbe" 201 | 202 | uriResource = "resource" 203 | uriWebtop = "webtop" 204 | ) 205 | 206 | func (p *LIC) MarshalJSON() ([]byte, error) { 207 | var dto LICDTO 208 | marshal(&dto, p) 209 | return json.Marshal(dto) 210 | } 211 | 212 | func (p *LIC) UnmarshalJSON(b []byte) error { 213 | var dto LICDTO 214 | err := json.Unmarshal(b, &dto) 215 | if err != nil { 216 | return err 217 | } 218 | return marshal(p, &dto) 219 | } 220 | 221 | func (b *BigIP) getLicensePool() (*LicensePool, error) { 222 | var licensePool LicensePool 223 | err, _ := b.getForEntity(&licensePool, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriPur, uriLicn) 224 | if err != nil { 225 | return nil, err 226 | } 227 | // for loop over all returned license pools to check which one has available licenses 228 | // getAvailablePool(member[index_of_array].Uuid) 229 | // At the end change return statement to return only the UUID string of the one where license 230 | // is available 231 | return &licensePool, nil 232 | } 233 | 234 | // VirtualAddresses returns a list of virtual addresses. 235 | func (b *BigIP) LIC() (*LIC, error) { 236 | var va LIC 237 | licensePool, licensePoolErr := b.getLicensePool() 238 | if licensePoolErr != nil { 239 | return nil, licensePoolErr 240 | } 241 | err, _ := b.getForEntity(&va, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriPur, uriLicn, licensePool.Items[0].Uuid, uriMemb) 242 | if err != nil { 243 | return nil, err 244 | } 245 | return &va, nil 246 | } 247 | 248 | func (b *BigIP) CreateLIC(deviceAddress string, username string, password string) error { 249 | config := &LIC{ 250 | DeviceAddress: deviceAddress, 251 | Username: username, 252 | Password: password, 253 | } 254 | 255 | licensePool, licensePoolErr := b.getLicensePool() 256 | if licensePoolErr != nil { 257 | return licensePoolErr 258 | } 259 | 260 | return b.post(config, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriPur, uriLicn, licensePool.Items[0].Uuid, uriMemb) 261 | } 262 | 263 | func (b *BigIP) ModifyLIC(config *LIC) error { 264 | licensePool, licensePoolErr := b.getLicensePool() 265 | if licensePoolErr != nil { 266 | return licensePoolErr 267 | } 268 | return b.post(config, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriPur, uriLicn, licensePool.Items[0].Uuid, uriMemb) 269 | } 270 | 271 | func (b *BigIP) LICs() (*LIC, error) { 272 | var members LIC 273 | licensePool, licensePoolErr := b.getLicensePool() 274 | if licensePoolErr != nil { 275 | return nil, licensePoolErr 276 | } 277 | err, _ := b.getForEntity(&members, uriMgmt, uriCm, uriDiv, uriLins, uriPoo, uriPur, uriLicn, licensePool.Items[0].Uuid, uriMemb) 278 | 279 | if err != nil { 280 | return nil, err 281 | } 282 | 283 | return &members, nil 284 | } 285 | 286 | func (b *BigIP) CreateDevice(name, configsyncIp, mirrorIp, mirrorSecondaryIp string) error { 287 | config := &Device{ 288 | Name: name, 289 | ConfigsyncIp: configsyncIp, 290 | MirrorIp: mirrorIp, 291 | MirrorSecondaryIp: mirrorSecondaryIp, 292 | } 293 | 294 | return b.post(config, uriCm, uriDiv) 295 | } 296 | 297 | // API does not work, you cannot modify API issue 298 | func (b *BigIP) ModifyDevice(config *Device) error { 299 | return b.put(config, uriCm, uriDiv) 300 | } 301 | 302 | func (b *BigIP) DeleteDevice(name string) error { 303 | return b.delete(uriCm, uriDiv, name) 304 | } 305 | 306 | func (b *BigIP) Devices(name string) (*Device, error) { 307 | var device Device 308 | err, _ := b.getForEntity(&device, uriCm, uriDiv, name) 309 | 310 | if err != nil { 311 | return nil, err 312 | } 313 | 314 | return &device, nil 315 | } 316 | 317 | // GetDevices returns a list of the bigip's in the cluster. 318 | func (b *BigIP) GetDevices() ([]Device, error) { 319 | var devices Devices 320 | err, _ := b.getForEntity(&devices, uriCm, uriDiv) 321 | 322 | if err != nil { 323 | return nil, err 324 | } 325 | 326 | return devices.Devices, nil 327 | } 328 | 329 | func (b *BigIP) CreateDevicegroup(p *Devicegroup) error { 330 | return b.post(p, uriCm, uriDG) 331 | } 332 | 333 | func (b *BigIP) UpdateDevicegroup(name string, p *Devicegroup) error { 334 | return b.put(p, uriCm, uriDG, name) 335 | } 336 | 337 | func (b *BigIP) ModifyDevicegroup(config *Devicegroup) error { 338 | return b.put(config, uriCm, uriDG) 339 | } 340 | 341 | func (b *BigIP) Devicegroups(name string) (*Devicegroup, error) { 342 | var devicegroup Devicegroup 343 | err, _ := b.getForEntity(&devicegroup, uriCm, uriDG, name) 344 | if err != nil { 345 | return nil, err 346 | } 347 | 348 | return &devicegroup, nil 349 | } 350 | 351 | func (b *BigIP) DeleteDevicegroup(name string) error { 352 | return b.delete(uriCm, uriDG, name) 353 | } 354 | 355 | func (b *BigIP) DeleteDevicegroupDevices(name, rname string) error { 356 | return b.delete(uriCm, uriDG, name, uriDevices, rname) 357 | } 358 | 359 | func (b *BigIP) DevicegroupsDevices(name, rname string) (*Devicegroup, error) { 360 | var devicegroup Devicegroup 361 | err, _ := b.getForEntity(&devicegroup, uriCm, uriDG, name, uriDevices, rname) 362 | if err != nil { 363 | return nil, err 364 | } 365 | 366 | return &devicegroup, nil 367 | } 368 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/format.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "reflect" 23 | "strconv" 24 | "strings" 25 | ) 26 | 27 | // supportedFlags is a list of all the character flags supported by fmt package. 28 | const supportedFlags = "0-+# " 29 | 30 | // formatState implements the fmt.Formatter interface and contains information 31 | // about the state of a formatting operation. The NewFormatter function can 32 | // be used to get a new Formatter which can be used directly as arguments 33 | // in standard fmt package printing calls. 34 | type formatState struct { 35 | value interface{} 36 | fs fmt.State 37 | depth int 38 | pointers map[uintptr]int 39 | ignoreNextType bool 40 | cs *ConfigState 41 | } 42 | 43 | // buildDefaultFormat recreates the original format string without precision 44 | // and width information to pass in to fmt.Sprintf in the case of an 45 | // unrecognized type. Unless new types are added to the language, this 46 | // function won't ever be called. 47 | func (f *formatState) buildDefaultFormat() (format string) { 48 | buf := bytes.NewBuffer(percentBytes) 49 | 50 | for _, flag := range supportedFlags { 51 | if f.fs.Flag(int(flag)) { 52 | buf.WriteRune(flag) 53 | } 54 | } 55 | 56 | buf.WriteRune('v') 57 | 58 | format = buf.String() 59 | return format 60 | } 61 | 62 | // constructOrigFormat recreates the original format string including precision 63 | // and width information to pass along to the standard fmt package. This allows 64 | // automatic deferral of all format strings this package doesn't support. 65 | func (f *formatState) constructOrigFormat(verb rune) (format string) { 66 | buf := bytes.NewBuffer(percentBytes) 67 | 68 | for _, flag := range supportedFlags { 69 | if f.fs.Flag(int(flag)) { 70 | buf.WriteRune(flag) 71 | } 72 | } 73 | 74 | if width, ok := f.fs.Width(); ok { 75 | buf.WriteString(strconv.Itoa(width)) 76 | } 77 | 78 | if precision, ok := f.fs.Precision(); ok { 79 | buf.Write(precisionBytes) 80 | buf.WriteString(strconv.Itoa(precision)) 81 | } 82 | 83 | buf.WriteRune(verb) 84 | 85 | format = buf.String() 86 | return format 87 | } 88 | 89 | // unpackValue returns values inside of non-nil interfaces when possible and 90 | // ensures that types for values which have been unpacked from an interface 91 | // are displayed when the show types flag is also set. 92 | // This is useful for data types like structs, arrays, slices, and maps which 93 | // can contain varying types packed inside an interface. 94 | func (f *formatState) unpackValue(v reflect.Value) reflect.Value { 95 | if v.Kind() == reflect.Interface { 96 | f.ignoreNextType = false 97 | if !v.IsNil() { 98 | v = v.Elem() 99 | } 100 | } 101 | return v 102 | } 103 | 104 | // formatPtr handles formatting of pointers by indirecting them as necessary. 105 | func (f *formatState) formatPtr(v reflect.Value) { 106 | // Display nil if top level pointer is nil. 107 | showTypes := f.fs.Flag('#') 108 | if v.IsNil() && (!showTypes || f.ignoreNextType) { 109 | f.fs.Write(nilAngleBytes) 110 | return 111 | } 112 | 113 | // Remove pointers at or below the current depth from map used to detect 114 | // circular refs. 115 | for k, depth := range f.pointers { 116 | if depth >= f.depth { 117 | delete(f.pointers, k) 118 | } 119 | } 120 | 121 | // Keep list of all dereferenced pointers to possibly show later. 122 | pointerChain := make([]uintptr, 0) 123 | 124 | // Figure out how many levels of indirection there are by derferencing 125 | // pointers and unpacking interfaces down the chain while detecting circular 126 | // references. 127 | nilFound := false 128 | cycleFound := false 129 | indirects := 0 130 | ve := v 131 | for ve.Kind() == reflect.Ptr { 132 | if ve.IsNil() { 133 | nilFound = true 134 | break 135 | } 136 | indirects++ 137 | addr := ve.Pointer() 138 | pointerChain = append(pointerChain, addr) 139 | if pd, ok := f.pointers[addr]; ok && pd < f.depth { 140 | cycleFound = true 141 | indirects-- 142 | break 143 | } 144 | f.pointers[addr] = f.depth 145 | 146 | ve = ve.Elem() 147 | if ve.Kind() == reflect.Interface { 148 | if ve.IsNil() { 149 | nilFound = true 150 | break 151 | } 152 | ve = ve.Elem() 153 | } 154 | } 155 | 156 | // Display type or indirection level depending on flags. 157 | if showTypes && !f.ignoreNextType { 158 | f.fs.Write(openParenBytes) 159 | f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) 160 | f.fs.Write([]byte(ve.Type().String())) 161 | f.fs.Write(closeParenBytes) 162 | } else { 163 | if nilFound || cycleFound { 164 | indirects += strings.Count(ve.Type().String(), "*") 165 | } 166 | f.fs.Write(openAngleBytes) 167 | f.fs.Write([]byte(strings.Repeat("*", indirects))) 168 | f.fs.Write(closeAngleBytes) 169 | } 170 | 171 | // Display pointer information depending on flags. 172 | if f.fs.Flag('+') && (len(pointerChain) > 0) { 173 | f.fs.Write(openParenBytes) 174 | for i, addr := range pointerChain { 175 | if i > 0 { 176 | f.fs.Write(pointerChainBytes) 177 | } 178 | printHexPtr(f.fs, addr) 179 | } 180 | f.fs.Write(closeParenBytes) 181 | } 182 | 183 | // Display dereferenced value. 184 | switch { 185 | case nilFound == true: 186 | f.fs.Write(nilAngleBytes) 187 | 188 | case cycleFound == true: 189 | f.fs.Write(circularShortBytes) 190 | 191 | default: 192 | f.ignoreNextType = true 193 | f.format(ve) 194 | } 195 | } 196 | 197 | // format is the main workhorse for providing the Formatter interface. It 198 | // uses the passed reflect value to figure out what kind of object we are 199 | // dealing with and formats it appropriately. It is a recursive function, 200 | // however circular data structures are detected and handled properly. 201 | func (f *formatState) format(v reflect.Value) { 202 | // Handle invalid reflect values immediately. 203 | kind := v.Kind() 204 | if kind == reflect.Invalid { 205 | f.fs.Write(invalidAngleBytes) 206 | return 207 | } 208 | 209 | // Handle pointers specially. 210 | if kind == reflect.Ptr { 211 | f.formatPtr(v) 212 | return 213 | } 214 | 215 | // Print type information unless already handled elsewhere. 216 | if !f.ignoreNextType && f.fs.Flag('#') { 217 | f.fs.Write(openParenBytes) 218 | f.fs.Write([]byte(v.Type().String())) 219 | f.fs.Write(closeParenBytes) 220 | } 221 | f.ignoreNextType = false 222 | 223 | // Call Stringer/error interfaces if they exist and the handle methods 224 | // flag is enabled. 225 | if !f.cs.DisableMethods { 226 | if (kind != reflect.Invalid) && (kind != reflect.Interface) { 227 | if handled := handleMethods(f.cs, f.fs, v); handled { 228 | return 229 | } 230 | } 231 | } 232 | 233 | switch kind { 234 | case reflect.Invalid: 235 | // Do nothing. We should never get here since invalid has already 236 | // been handled above. 237 | 238 | case reflect.Bool: 239 | printBool(f.fs, v.Bool()) 240 | 241 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 242 | printInt(f.fs, v.Int(), 10) 243 | 244 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 245 | printUint(f.fs, v.Uint(), 10) 246 | 247 | case reflect.Float32: 248 | printFloat(f.fs, v.Float(), 32) 249 | 250 | case reflect.Float64: 251 | printFloat(f.fs, v.Float(), 64) 252 | 253 | case reflect.Complex64: 254 | printComplex(f.fs, v.Complex(), 32) 255 | 256 | case reflect.Complex128: 257 | printComplex(f.fs, v.Complex(), 64) 258 | 259 | case reflect.Slice: 260 | if v.IsNil() { 261 | f.fs.Write(nilAngleBytes) 262 | break 263 | } 264 | fallthrough 265 | 266 | case reflect.Array: 267 | f.fs.Write(openBracketBytes) 268 | f.depth++ 269 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 270 | f.fs.Write(maxShortBytes) 271 | } else { 272 | numEntries := v.Len() 273 | for i := 0; i < numEntries; i++ { 274 | if i > 0 { 275 | f.fs.Write(spaceBytes) 276 | } 277 | f.ignoreNextType = true 278 | f.format(f.unpackValue(v.Index(i))) 279 | } 280 | } 281 | f.depth-- 282 | f.fs.Write(closeBracketBytes) 283 | 284 | case reflect.String: 285 | f.fs.Write([]byte(v.String())) 286 | 287 | case reflect.Interface: 288 | // The only time we should get here is for nil interfaces due to 289 | // unpackValue calls. 290 | if v.IsNil() { 291 | f.fs.Write(nilAngleBytes) 292 | } 293 | 294 | case reflect.Ptr: 295 | // Do nothing. We should never get here since pointers have already 296 | // been handled above. 297 | 298 | case reflect.Map: 299 | // nil maps should be indicated as different than empty maps 300 | if v.IsNil() { 301 | f.fs.Write(nilAngleBytes) 302 | break 303 | } 304 | 305 | f.fs.Write(openMapBytes) 306 | f.depth++ 307 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 308 | f.fs.Write(maxShortBytes) 309 | } else { 310 | keys := v.MapKeys() 311 | if f.cs.SortKeys { 312 | sortValues(keys, f.cs) 313 | } 314 | for i, key := range keys { 315 | if i > 0 { 316 | f.fs.Write(spaceBytes) 317 | } 318 | f.ignoreNextType = true 319 | f.format(f.unpackValue(key)) 320 | f.fs.Write(colonBytes) 321 | f.ignoreNextType = true 322 | f.format(f.unpackValue(v.MapIndex(key))) 323 | } 324 | } 325 | f.depth-- 326 | f.fs.Write(closeMapBytes) 327 | 328 | case reflect.Struct: 329 | numFields := v.NumField() 330 | f.fs.Write(openBraceBytes) 331 | f.depth++ 332 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 333 | f.fs.Write(maxShortBytes) 334 | } else { 335 | vt := v.Type() 336 | for i := 0; i < numFields; i++ { 337 | if i > 0 { 338 | f.fs.Write(spaceBytes) 339 | } 340 | vtf := vt.Field(i) 341 | if f.fs.Flag('+') || f.fs.Flag('#') { 342 | f.fs.Write([]byte(vtf.Name)) 343 | f.fs.Write(colonBytes) 344 | } 345 | f.format(f.unpackValue(v.Field(i))) 346 | } 347 | } 348 | f.depth-- 349 | f.fs.Write(closeBraceBytes) 350 | 351 | case reflect.Uintptr: 352 | printHexPtr(f.fs, uintptr(v.Uint())) 353 | 354 | case reflect.UnsafePointer, reflect.Chan, reflect.Func: 355 | printHexPtr(f.fs, v.Pointer()) 356 | 357 | // There were not any other types at the time this code was written, but 358 | // fall back to letting the default fmt package handle it if any get added. 359 | default: 360 | format := f.buildDefaultFormat() 361 | if v.CanInterface() { 362 | fmt.Fprintf(f.fs, format, v.Interface()) 363 | } else { 364 | fmt.Fprintf(f.fs, format, v.String()) 365 | } 366 | } 367 | } 368 | 369 | // Format satisfies the fmt.Formatter interface. See NewFormatter for usage 370 | // details. 371 | func (f *formatState) Format(fs fmt.State, verb rune) { 372 | f.fs = fs 373 | 374 | // Use standard formatting for verbs that are not v. 375 | if verb != 'v' { 376 | format := f.constructOrigFormat(verb) 377 | fmt.Fprintf(fs, format, f.value) 378 | return 379 | } 380 | 381 | if f.value == nil { 382 | if fs.Flag('#') { 383 | fs.Write(interfaceBytes) 384 | } 385 | fs.Write(nilAngleBytes) 386 | return 387 | } 388 | 389 | f.format(reflect.ValueOf(f.value)) 390 | } 391 | 392 | // newFormatter is a helper function to consolidate the logic from the various 393 | // public methods which take varying config states. 394 | func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { 395 | fs := &formatState{value: v, cs: cs} 396 | fs.pointers = make(map[uintptr]int) 397 | return fs 398 | } 399 | 400 | /* 401 | NewFormatter returns a custom formatter that satisfies the fmt.Formatter 402 | interface. As a result, it integrates cleanly with standard fmt package 403 | printing functions. The formatter is useful for inline printing of smaller data 404 | types similar to the standard %v format specifier. 405 | 406 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 407 | addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb 408 | combinations. Any other verbs such as %x and %q will be sent to the the 409 | standard fmt package for formatting. In addition, the custom formatter ignores 410 | the width and precision arguments (however they will still work on the format 411 | specifiers not handled by the custom formatter). 412 | 413 | Typically this function shouldn't be called directly. It is much easier to make 414 | use of the custom formatter by calling one of the convenience functions such as 415 | Printf, Println, or Fprintf. 416 | */ 417 | func NewFormatter(v interface{}) fmt.Formatter { 418 | return newFormatter(&Config, v) 419 | } 420 | -------------------------------------------------------------------------------- /apm.go: -------------------------------------------------------------------------------- 1 | package bigip 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | ) 7 | 8 | type ( 9 | WebtopType string 10 | CustomizationType string 11 | InitialState string 12 | LinkType string 13 | ) 14 | 15 | const ( 16 | WebtopTypePortal WebtopType = "portal-access" 17 | WebtopTypeFull = "full" 18 | WebtopTypeNetwork = "network-access" 19 | ) 20 | 21 | const ( 22 | CustomizationTypeModern CustomizationType = "Modern" 23 | CustomizationTypeStandard = "Standard" 24 | ) 25 | 26 | const ( 27 | InitialStateCollapsed InitialState = "Collapsed" 28 | InitialStateExpanded = "Expanded" 29 | ) 30 | 31 | const ( 32 | LinkTypeUri LinkType = "uri" 33 | ) 34 | 35 | const ( 36 | uriAccess = "access" 37 | uriAccessPolicy = "access-policy" 38 | ) 39 | 40 | // Some endpoints have a "booledString" a boolean value that is represented as a string in the json payload 41 | type BooledString bool 42 | 43 | func (b BooledString) MarshalJSON() ([]byte, error) { 44 | str := "false" 45 | if b { 46 | str = "true" 47 | } 48 | return json.Marshal(str) 49 | } 50 | 51 | func (b BooledString) UnmarshalJSON(data []byte) error { 52 | var str string 53 | if err := json.Unmarshal(data, &str); err != nil { 54 | return err 55 | } 56 | b = str == "true" 57 | return nil 58 | } 59 | 60 | // Values in WebtopConfig are updateable 61 | type WebtopConfig struct { 62 | Description string `json:"description,omitempty"` 63 | LinkType LinkType `json:"linkType,omitempty"` 64 | CustomizationGroup string `json:"customizationGroup"` 65 | Type WebtopType `json:"webtopType,omitempty"` 66 | CustomizationType CustomizationType `json:"customizationType,omitempty"` 67 | LocationSpecific BooledString `json:"locationSpecific"` 68 | MinimizeToTray BooledString `json:"minimizeToTray"` 69 | ShowSearch BooledString `json:"showSearch"` 70 | WarningOnClose BooledString `json:"warningOnClose"` 71 | UrlEntryField BooledString `json:"urlEntryField"` 72 | ResourceSearch BooledString `json:"resourceSearch"` 73 | InitialState InitialState `json:"initialState,omitempty"` 74 | } 75 | 76 | // Only the values within WebtopConfig can be updated. Any changes made to non-config values will be ignored when using UpdateWebtop. 77 | type Webtop struct { 78 | Name string `json:"name,omitempty"` 79 | Partition string `json:"partition,omitempty"` 80 | TMPartition string `json:"tmPartition,omitempty"` 81 | WebtopConfig 82 | } 83 | 84 | type WebtopRead struct { 85 | Webtop 86 | FullPath string `json:"fullPath,omitempty"` 87 | Generation int `json:"generation,omitempty"` 88 | SelfLink string `json:"selfLink,omitempty"` 89 | CustomizationGroupReference struct { 90 | Link string `json:"link,omitempty"` 91 | } `json:"customizationGroupReference,omitempty"` 92 | } 93 | 94 | func (b *BigIP) CreateWebtop(ctx context.Context, webtop Webtop) error { 95 | if ctx.Err() != nil { 96 | return ctx.Err() 97 | } 98 | return b.post(webtop, uriMgmt, uriTm, uriApm, uriResource, uriWebtop) 99 | } 100 | 101 | func (b *BigIP) DeleteWebtop(ctx context.Context, name string) error { 102 | if ctx.Err() != nil { 103 | return ctx.Err() 104 | } 105 | return b.delete(uriMgmt, uriTm, uriApm, uriResource, uriWebtop, name) 106 | } 107 | 108 | func (b *BigIP) GetWebtop(ctx context.Context, name string) (*WebtopRead, error) { 109 | if ctx.Err() != nil { 110 | return nil, ctx.Err() 111 | } 112 | var webtop WebtopRead 113 | err, _ := b.getForEntity(&webtop, uriMgmt, uriTm, uriApm, uriResource, uriWebtop, name) 114 | return &webtop, err 115 | } 116 | 117 | func (b *BigIP) ModifyWebtop(ctx context.Context, name string, webtop WebtopConfig) error { 118 | if ctx.Err() != nil { 119 | return ctx.Err() 120 | } 121 | return b.patch(webtop, uriMgmt, uriTm, uriApm, uriResource, uriWebtop, name) 122 | } 123 | 124 | // AccessProfiles contains a list of all access profiles on the BIG-IP system. 125 | type AccessProfiles struct { 126 | AccessProfiles []AccessProfile `json:"items"` 127 | } 128 | 129 | // AccessProfile contains information about each access profile. 130 | type AccessProfile struct { 131 | Name string `json:"name,omitempty"` 132 | Partition string `json:"partition,omitempty"` 133 | FullPath string `json:"fullPath,omitempty"` 134 | Generation int `json:"generation,omitempty"` 135 | SelfLink string `json:"selfLink,omitempty"` 136 | Kind string `json:"kind,omitempty"` 137 | DefaultsFrom string `json:"defaultsFrom,omitempty"` 138 | Description string `json:"description,omitempty"` 139 | AcceptLanguages []string `json:"acceptLanguages,omitempty"` 140 | AccessPolicy string `json:"accessPolicy,omitempty"` 141 | AccessPolicyTimeout int `json:"accessPolicyTimeout,omitempty"` 142 | CertificateKey string `json:"certificateKey,omitempty"` 143 | CompressGzipLevel int `json:"compressGzipLevel,omitempty"` 144 | CookieNames string `json:"cookieNames,omitempty"` 145 | CustomizationKey string `json:"customizationKey,omitempty"` 146 | DefaultLanguage string `json:"defaultLanguage,omitempty"` 147 | Domain string `json:"domain,omitempty"` 148 | DomainCookie string `json:"domainCookie,omitempty"` 149 | DomainMode string `json:"domainMode,omitempty"` 150 | EpsProfile string `json:"epsProfile,omitempty"` 151 | ErrorMapItem string `json:"errorMapItem,omitempty"` 152 | EnforcePolicy string `json:"enforcePolicy,omitempty"` 153 | FrameworkInstallationID string `json:"frameworkInstallationId,omitempty"` 154 | GenerationAction string `json:"generationAction,omitempty"` 155 | GzipLevel int `json:"gzipLevel,omitempty"` 156 | HTTPOnlyCookie string `json:"httponlyCookie,omitempty"` 157 | InactivityTimeout int `json:"inactivityTimeout,omitempty"` 158 | LogSettings []string `json:"logSettings,omitempty"` 159 | LogoutURIInclude string `json:"logoutUriInclude,omitempty"` 160 | LogoutURITimeout int `json:"logoutUriTimeout,omitempty"` 161 | MaxConcurrentSessions int `json:"maxConcurrentSessions,omitempty"` 162 | MaxConcurrentUsers int `json:"maxConcurrentUsers,omitempty"` 163 | MaxFailureDelay int `json:"maxFailureDelay,omitempty"` 164 | MaxInProgressSessions int `json:"maxInProgressSessions,omitempty"` 165 | MaxSessionTimeout int `json:"maxSessionTimeout,omitempty"` 166 | MinFailureDelay int `json:"minFailureDelay,omitempty"` 167 | ModifiedSinceLastPolicySync string `json:"modifiedSinceLastPolicySync,omitempty"` 168 | NtlmConnPool string `json:"ntlmConnPool,omitempty"` 169 | PersistentCookie string `json:"persistentCookie,omitempty"` 170 | RestrictToSingleClientIP string `json:"restrictToSingleClientIp,omitempty"` 171 | SamesiteCookie string `json:"samesiteCookie,omitempty"` 172 | SamesiteCookieAttrValue string `json:"samesiteCookieAttrValue,omitempty"` 173 | Scope string `json:"scope,omitempty"` 174 | ScopeFilteringProfile string `json:"scopeFilteringProfile,omitempty"` 175 | SecureCookie string `json:"secureCookie,omitempty"` 176 | Services []string `json:"services,omitempty"` 177 | SsoName string `json:"ssoName,omitempty"` 178 | TmGeneration int `json:"tmGeneration,omitempty"` 179 | Type string `json:"type,omitempty"` 180 | UserIdentityMethod string `json:"userIdentityMethod,omitempty"` 181 | UseHTTP503OnError string `json:"useHttp_503OnError,omitempty"` 182 | UsernameCookie string `json:"usernameCookie,omitempty"` 183 | WebtopRedirectOnRootURI string `json:"webtopRedirectOnRootUri,omitempty"` 184 | DomainGroupsReference struct { 185 | Link string `json:"link,omitempty"` 186 | IsSubcollection bool `json:"isSubcollection,omitempty"` 187 | } `json:"domainGroupsReference,omitempty"` 188 | } 189 | 190 | // AccessPolicies contains a list of all access policies on the BIG-IP system. 191 | type AccessPolicies struct { 192 | Kind string `json:"kind,omitempty"` 193 | SelfLink string `json:"selfLink,omitempty"` 194 | Items []AccessPolicy `json:"items"` 195 | } 196 | 197 | // PolicyItem represents an item within an access policy. 198 | type PolicyItem struct { 199 | Name string `json:"name,omitempty"` 200 | Partition string `json:"partition,omitempty"` 201 | Priority int `json:"priority,omitempty"` 202 | NameReference struct { 203 | Link string `json:"link,omitempty"` 204 | } `json:"nameReference,omitempty"` 205 | } 206 | 207 | // PerReqPolicyProperty represents per-request policy properties. 208 | type PerReqPolicyProperty struct { 209 | Name string `json:"name,omitempty"` 210 | Partition string `json:"partition,omitempty"` 211 | IncompleteAction string `json:"incompleteAction,omitempty"` 212 | } 213 | 214 | // AccessPolicy contains information about each access policy. 215 | type AccessPolicy struct { 216 | Kind string `json:"kind,omitempty"` 217 | Name string `json:"name,omitempty"` 218 | Partition string `json:"partition,omitempty"` 219 | FullPath string `json:"fullPath,omitempty"` 220 | Generation int `json:"generation,omitempty"` 221 | SelfLink string `json:"selfLink,omitempty"` 222 | DefaultEnding string `json:"defaultEnding,omitempty"` 223 | DefaultEndingReference struct { 224 | Link string `json:"link,omitempty"` 225 | } `json:"defaultEndingReference,omitempty"` 226 | MaxMacroLoopCount int `json:"maxMacroLoopCount,omitempty"` 227 | OneshotMacro string `json:"oneshotMacro,omitempty"` 228 | StartItem string `json:"startItem,omitempty"` 229 | StartItemReference struct { 230 | Link string `json:"link,omitempty"` 231 | } `json:"startItemReference,omitempty"` 232 | Type string `json:"type,omitempty"` 233 | Items []PolicyItem `json:"items,omitempty"` 234 | PerReqPolicyProperties []PerReqPolicyProperty `json:"perReqPolicyProperties,omitempty"` 235 | } 236 | 237 | // GetAccessProfile gets an access profile by name. Returns nil if the access profile does not exist 238 | func (b *BigIP) GetAccessProfile(name string) (*AccessProfile, error) { 239 | var accessProfile AccessProfile 240 | err, ok := b.getForEntity(&accessProfile, uriMgmt, uriTm, uriApm, uriProfile, uriAccess, name) 241 | if err != nil { 242 | return nil, err 243 | } 244 | 245 | if !ok { 246 | return nil, nil 247 | } 248 | 249 | return &accessProfile, nil 250 | } 251 | 252 | // AccessProfiles returns a list of all access profiles 253 | func (b *BigIP) AccessProfiles() (*AccessProfiles, error) { 254 | var accessProfiles AccessProfiles 255 | err, _ := b.getForEntity(&accessProfiles, uriMgmt, uriTm, uriApm, uriProfile, uriAccess) 256 | if err != nil { 257 | return nil, err 258 | } 259 | 260 | return &accessProfiles, nil 261 | } 262 | 263 | // CreateAccessProfile adds a new access profile to the BIG-IP system. 264 | func (b *BigIP) CreateAccessProfile(config *AccessProfile) error { 265 | return b.post(config, uriMgmt, uriTm, uriApm, uriProfile, uriAccess) 266 | } 267 | 268 | // DeleteAccessProfile removes an access profile. 269 | func (b *BigIP) DeleteAccessProfile(name string) error { 270 | return b.delete(uriMgmt, uriTm, uriApm, uriProfile, uriAccess, name) 271 | } 272 | 273 | // ModifyAccessProfile allows you to change any attribute of an access profile. 274 | // Fields that can be modified are referenced in the AccessProfile struct. 275 | func (b *BigIP) ModifyAccessProfile(name string, config *AccessProfile) error { 276 | return b.patch(config, uriMgmt, uriTm, uriApm, uriProfile, uriAccess, name) 277 | } 278 | 279 | // GetAccessPolicy gets an access policy by name. Returns nil if the access policy does not exist 280 | func (b *BigIP) GetAccessPolicy(name string) (*AccessPolicy, error) { 281 | var accessPolicy AccessPolicy 282 | err, ok := b.getForEntity(&accessPolicy, uriMgmt, uriTm, uriApm, uriPolicy, uriAccessPolicy, name) 283 | if err != nil { 284 | return nil, err 285 | } 286 | 287 | if !ok { 288 | return nil, nil 289 | } 290 | 291 | return &accessPolicy, nil 292 | } 293 | 294 | // AccessPolicies returns a list of all access policies 295 | func (b *BigIP) AccessPolicies() (*AccessPolicies, error) { 296 | var accessPolicies AccessPolicies 297 | err, _ := b.getForEntity(&accessPolicies, uriMgmt, uriTm, uriApm, uriPolicy, uriAccessPolicy) 298 | if err != nil { 299 | return nil, err 300 | } 301 | 302 | return &accessPolicies, nil 303 | } 304 | 305 | // CreateAccessPolicy adds a new access policy to the BIG-IP system. 306 | func (b *BigIP) CreateAccessPolicy(config *AccessPolicy) error { 307 | return b.post(config, uriMgmt, uriTm, uriApm, uriPolicy, uriAccessPolicy) 308 | } 309 | 310 | // DeleteAccessPolicy removes an access policy. 311 | func (b *BigIP) DeleteAccessPolicy(name string) error { 312 | return b.delete(uriMgmt, uriTm, uriApm, uriPolicy, uriAccessPolicy, name) 313 | } 314 | 315 | // ModifyAccessPolicy allows you to change any attribute of an access policy. 316 | // Fields that can be modified are referenced in the AccessPolicy struct. 317 | func (b *BigIP) ModifyAccessPolicy(name string, config *AccessPolicy) error { 318 | return b.patch(config, uriMgmt, uriTm, uriApm, uriPolicy, uriAccessPolicy, name) 319 | } 320 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "io" 23 | "os" 24 | ) 25 | 26 | // ConfigState houses the configuration options used by spew to format and 27 | // display values. There is a global instance, Config, that is used to control 28 | // all top-level Formatter and Dump functionality. Each ConfigState instance 29 | // provides methods equivalent to the top-level functions. 30 | // 31 | // The zero value for ConfigState provides no indentation. You would typically 32 | // want to set it to a space or a tab. 33 | // 34 | // Alternatively, you can use NewDefaultConfig to get a ConfigState instance 35 | // with default settings. See the documentation of NewDefaultConfig for default 36 | // values. 37 | type ConfigState struct { 38 | // Indent specifies the string to use for each indentation level. The 39 | // global config instance that all top-level functions use set this to a 40 | // single space by default. If you would like more indentation, you might 41 | // set this to a tab with "\t" or perhaps two spaces with " ". 42 | Indent string 43 | 44 | // MaxDepth controls the maximum number of levels to descend into nested 45 | // data structures. The default, 0, means there is no limit. 46 | // 47 | // NOTE: Circular data structures are properly detected, so it is not 48 | // necessary to set this value unless you specifically want to limit deeply 49 | // nested data structures. 50 | MaxDepth int 51 | 52 | // DisableMethods specifies whether or not error and Stringer interfaces are 53 | // invoked for types that implement them. 54 | DisableMethods bool 55 | 56 | // DisablePointerMethods specifies whether or not to check for and invoke 57 | // error and Stringer interfaces on types which only accept a pointer 58 | // receiver when the current type is not a pointer. 59 | // 60 | // NOTE: This might be an unsafe action since calling one of these methods 61 | // with a pointer receiver could technically mutate the value, however, 62 | // in practice, types which choose to satisify an error or Stringer 63 | // interface with a pointer receiver should not be mutating their state 64 | // inside these interface methods. As a result, this option relies on 65 | // access to the unsafe package, so it will not have any effect when 66 | // running in environments without access to the unsafe package such as 67 | // Google App Engine or with the "safe" build tag specified. 68 | DisablePointerMethods bool 69 | 70 | // DisablePointerAddresses specifies whether to disable the printing of 71 | // pointer addresses. This is useful when diffing data structures in tests. 72 | DisablePointerAddresses bool 73 | 74 | // DisableCapacities specifies whether to disable the printing of capacities 75 | // for arrays, slices, maps and channels. This is useful when diffing 76 | // data structures in tests. 77 | DisableCapacities bool 78 | 79 | // ContinueOnMethod specifies whether or not recursion should continue once 80 | // a custom error or Stringer interface is invoked. The default, false, 81 | // means it will print the results of invoking the custom error or Stringer 82 | // interface and return immediately instead of continuing to recurse into 83 | // the internals of the data type. 84 | // 85 | // NOTE: This flag does not have any effect if method invocation is disabled 86 | // via the DisableMethods or DisablePointerMethods options. 87 | ContinueOnMethod bool 88 | 89 | // SortKeys specifies map keys should be sorted before being printed. Use 90 | // this to have a more deterministic, diffable output. Note that only 91 | // native types (bool, int, uint, floats, uintptr and string) and types 92 | // that support the error or Stringer interfaces (if methods are 93 | // enabled) are supported, with other types sorted according to the 94 | // reflect.Value.String() output which guarantees display stability. 95 | SortKeys bool 96 | 97 | // SpewKeys specifies that, as a last resort attempt, map keys should 98 | // be spewed to strings and sorted by those strings. This is only 99 | // considered if SortKeys is true. 100 | SpewKeys bool 101 | } 102 | 103 | // Config is the active configuration of the top-level functions. 104 | // The configuration can be changed by modifying the contents of spew.Config. 105 | var Config = ConfigState{Indent: " "} 106 | 107 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 108 | // passed with a Formatter interface returned by c.NewFormatter. It returns 109 | // the formatted string as a value that satisfies error. See NewFormatter 110 | // for formatting details. 111 | // 112 | // This function is shorthand for the following syntax: 113 | // 114 | // fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) 115 | func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { 116 | return fmt.Errorf(format, c.convertArgs(a)...) 117 | } 118 | 119 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 120 | // passed with a Formatter interface returned by c.NewFormatter. It returns 121 | // the number of bytes written and any write error encountered. See 122 | // NewFormatter for formatting details. 123 | // 124 | // This function is shorthand for the following syntax: 125 | // 126 | // fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) 127 | func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { 128 | return fmt.Fprint(w, c.convertArgs(a)...) 129 | } 130 | 131 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 132 | // passed with a Formatter interface returned by c.NewFormatter. It returns 133 | // the number of bytes written and any write error encountered. See 134 | // NewFormatter for formatting details. 135 | // 136 | // This function is shorthand for the following syntax: 137 | // 138 | // fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) 139 | func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 140 | return fmt.Fprintf(w, format, c.convertArgs(a)...) 141 | } 142 | 143 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 144 | // passed with a Formatter interface returned by c.NewFormatter. See 145 | // NewFormatter for formatting details. 146 | // 147 | // This function is shorthand for the following syntax: 148 | // 149 | // fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) 150 | func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 151 | return fmt.Fprintln(w, c.convertArgs(a)...) 152 | } 153 | 154 | // Print is a wrapper for fmt.Print that treats each argument as if it were 155 | // passed with a Formatter interface returned by c.NewFormatter. It returns 156 | // the number of bytes written and any write error encountered. See 157 | // NewFormatter for formatting details. 158 | // 159 | // This function is shorthand for the following syntax: 160 | // 161 | // fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) 162 | func (c *ConfigState) Print(a ...interface{}) (n int, err error) { 163 | return fmt.Print(c.convertArgs(a)...) 164 | } 165 | 166 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 167 | // passed with a Formatter interface returned by c.NewFormatter. It returns 168 | // the number of bytes written and any write error encountered. See 169 | // NewFormatter for formatting details. 170 | // 171 | // This function is shorthand for the following syntax: 172 | // 173 | // fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) 174 | func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { 175 | return fmt.Printf(format, c.convertArgs(a)...) 176 | } 177 | 178 | // Println is a wrapper for fmt.Println that treats each argument as if it were 179 | // passed with a Formatter interface returned by c.NewFormatter. It returns 180 | // the number of bytes written and any write error encountered. See 181 | // NewFormatter for formatting details. 182 | // 183 | // This function is shorthand for the following syntax: 184 | // 185 | // fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) 186 | func (c *ConfigState) Println(a ...interface{}) (n int, err error) { 187 | return fmt.Println(c.convertArgs(a)...) 188 | } 189 | 190 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 191 | // passed with a Formatter interface returned by c.NewFormatter. It returns 192 | // the resulting string. See NewFormatter for formatting details. 193 | // 194 | // This function is shorthand for the following syntax: 195 | // 196 | // fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) 197 | func (c *ConfigState) Sprint(a ...interface{}) string { 198 | return fmt.Sprint(c.convertArgs(a)...) 199 | } 200 | 201 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 202 | // passed with a Formatter interface returned by c.NewFormatter. It returns 203 | // the resulting string. See NewFormatter for formatting details. 204 | // 205 | // This function is shorthand for the following syntax: 206 | // 207 | // fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) 208 | func (c *ConfigState) Sprintf(format string, a ...interface{}) string { 209 | return fmt.Sprintf(format, c.convertArgs(a)...) 210 | } 211 | 212 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 213 | // were passed with a Formatter interface returned by c.NewFormatter. It 214 | // returns the resulting string. See NewFormatter for formatting details. 215 | // 216 | // This function is shorthand for the following syntax: 217 | // 218 | // fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) 219 | func (c *ConfigState) Sprintln(a ...interface{}) string { 220 | return fmt.Sprintln(c.convertArgs(a)...) 221 | } 222 | 223 | /* 224 | NewFormatter returns a custom formatter that satisfies the fmt.Formatter 225 | interface. As a result, it integrates cleanly with standard fmt package 226 | printing functions. The formatter is useful for inline printing of smaller data 227 | types similar to the standard %v format specifier. 228 | 229 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 230 | addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb 231 | combinations. Any other verbs such as %x and %q will be sent to the the 232 | standard fmt package for formatting. In addition, the custom formatter ignores 233 | the width and precision arguments (however they will still work on the format 234 | specifiers not handled by the custom formatter). 235 | 236 | Typically this function shouldn't be called directly. It is much easier to make 237 | use of the custom formatter by calling one of the convenience functions such as 238 | c.Printf, c.Println, or c.Printf. 239 | */ 240 | func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { 241 | return newFormatter(c, v) 242 | } 243 | 244 | // Fdump formats and displays the passed arguments to io.Writer w. It formats 245 | // exactly the same as Dump. 246 | func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { 247 | fdump(c, w, a...) 248 | } 249 | 250 | /* 251 | Dump displays the passed parameters to standard out with newlines, customizable 252 | indentation, and additional debug information such as complete types and all 253 | pointer addresses used to indirect to the final value. It provides the 254 | following features over the built-in printing facilities provided by the fmt 255 | package: 256 | 257 | * Pointers are dereferenced and followed 258 | * Circular data structures are detected and handled properly 259 | * Custom Stringer/error interfaces are optionally invoked, including 260 | on unexported types 261 | * Custom types which only implement the Stringer/error interfaces via 262 | a pointer receiver are optionally invoked when passing non-pointer 263 | variables 264 | * Byte arrays and slices are dumped like the hexdump -C command which 265 | includes offsets, byte values in hex, and ASCII output 266 | 267 | The configuration options are controlled by modifying the public members 268 | of c. See ConfigState for options documentation. 269 | 270 | See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to 271 | get the formatted result as a string. 272 | */ 273 | func (c *ConfigState) Dump(a ...interface{}) { 274 | fdump(c, os.Stdout, a...) 275 | } 276 | 277 | // Sdump returns a string with the passed arguments formatted exactly the same 278 | // as Dump. 279 | func (c *ConfigState) Sdump(a ...interface{}) string { 280 | var buf bytes.Buffer 281 | fdump(c, &buf, a...) 282 | return buf.String() 283 | } 284 | 285 | // convertArgs accepts a slice of arguments and returns a slice of the same 286 | // length with each argument converted to a spew Formatter interface using 287 | // the ConfigState associated with s. 288 | func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { 289 | formatters = make([]interface{}, len(args)) 290 | for index, arg := range args { 291 | formatters[index] = newFormatter(c, arg) 292 | } 293 | return formatters 294 | } 295 | 296 | // NewDefaultConfig returns a ConfigState with the following default settings. 297 | // 298 | // Indent: " " 299 | // MaxDepth: 0 300 | // DisableMethods: false 301 | // DisablePointerMethods: false 302 | // ContinueOnMethod: false 303 | // SortKeys: false 304 | func NewDefaultConfig() *ConfigState { 305 | return &ConfigState{Indent: " "} 306 | } 307 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/dump.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "encoding/hex" 22 | "fmt" 23 | "io" 24 | "os" 25 | "reflect" 26 | "regexp" 27 | "strconv" 28 | "strings" 29 | ) 30 | 31 | var ( 32 | // uint8Type is a reflect.Type representing a uint8. It is used to 33 | // convert cgo types to uint8 slices for hexdumping. 34 | uint8Type = reflect.TypeOf(uint8(0)) 35 | 36 | // cCharRE is a regular expression that matches a cgo char. 37 | // It is used to detect character arrays to hexdump them. 38 | cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") 39 | 40 | // cUnsignedCharRE is a regular expression that matches a cgo unsigned 41 | // char. It is used to detect unsigned character arrays to hexdump 42 | // them. 43 | cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") 44 | 45 | // cUint8tCharRE is a regular expression that matches a cgo uint8_t. 46 | // It is used to detect uint8_t arrays to hexdump them. 47 | cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") 48 | ) 49 | 50 | // dumpState contains information about the state of a dump operation. 51 | type dumpState struct { 52 | w io.Writer 53 | depth int 54 | pointers map[uintptr]int 55 | ignoreNextType bool 56 | ignoreNextIndent bool 57 | cs *ConfigState 58 | } 59 | 60 | // indent performs indentation according to the depth level and cs.Indent 61 | // option. 62 | func (d *dumpState) indent() { 63 | if d.ignoreNextIndent { 64 | d.ignoreNextIndent = false 65 | return 66 | } 67 | d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) 68 | } 69 | 70 | // unpackValue returns values inside of non-nil interfaces when possible. 71 | // This is useful for data types like structs, arrays, slices, and maps which 72 | // can contain varying types packed inside an interface. 73 | func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { 74 | if v.Kind() == reflect.Interface && !v.IsNil() { 75 | v = v.Elem() 76 | } 77 | return v 78 | } 79 | 80 | // dumpPtr handles formatting of pointers by indirecting them as necessary. 81 | func (d *dumpState) dumpPtr(v reflect.Value) { 82 | // Remove pointers at or below the current depth from map used to detect 83 | // circular refs. 84 | for k, depth := range d.pointers { 85 | if depth >= d.depth { 86 | delete(d.pointers, k) 87 | } 88 | } 89 | 90 | // Keep list of all dereferenced pointers to show later. 91 | pointerChain := make([]uintptr, 0) 92 | 93 | // Figure out how many levels of indirection there are by dereferencing 94 | // pointers and unpacking interfaces down the chain while detecting circular 95 | // references. 96 | nilFound := false 97 | cycleFound := false 98 | indirects := 0 99 | ve := v 100 | for ve.Kind() == reflect.Ptr { 101 | if ve.IsNil() { 102 | nilFound = true 103 | break 104 | } 105 | indirects++ 106 | addr := ve.Pointer() 107 | pointerChain = append(pointerChain, addr) 108 | if pd, ok := d.pointers[addr]; ok && pd < d.depth { 109 | cycleFound = true 110 | indirects-- 111 | break 112 | } 113 | d.pointers[addr] = d.depth 114 | 115 | ve = ve.Elem() 116 | if ve.Kind() == reflect.Interface { 117 | if ve.IsNil() { 118 | nilFound = true 119 | break 120 | } 121 | ve = ve.Elem() 122 | } 123 | } 124 | 125 | // Display type information. 126 | d.w.Write(openParenBytes) 127 | d.w.Write(bytes.Repeat(asteriskBytes, indirects)) 128 | d.w.Write([]byte(ve.Type().String())) 129 | d.w.Write(closeParenBytes) 130 | 131 | // Display pointer information. 132 | if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { 133 | d.w.Write(openParenBytes) 134 | for i, addr := range pointerChain { 135 | if i > 0 { 136 | d.w.Write(pointerChainBytes) 137 | } 138 | printHexPtr(d.w, addr) 139 | } 140 | d.w.Write(closeParenBytes) 141 | } 142 | 143 | // Display dereferenced value. 144 | d.w.Write(openParenBytes) 145 | switch { 146 | case nilFound == true: 147 | d.w.Write(nilAngleBytes) 148 | 149 | case cycleFound == true: 150 | d.w.Write(circularBytes) 151 | 152 | default: 153 | d.ignoreNextType = true 154 | d.dump(ve) 155 | } 156 | d.w.Write(closeParenBytes) 157 | } 158 | 159 | // dumpSlice handles formatting of arrays and slices. Byte (uint8 under 160 | // reflection) arrays and slices are dumped in hexdump -C fashion. 161 | func (d *dumpState) dumpSlice(v reflect.Value) { 162 | // Determine whether this type should be hex dumped or not. Also, 163 | // for types which should be hexdumped, try to use the underlying data 164 | // first, then fall back to trying to convert them to a uint8 slice. 165 | var buf []uint8 166 | doConvert := false 167 | doHexDump := false 168 | numEntries := v.Len() 169 | if numEntries > 0 { 170 | vt := v.Index(0).Type() 171 | vts := vt.String() 172 | switch { 173 | // C types that need to be converted. 174 | case cCharRE.MatchString(vts): 175 | fallthrough 176 | case cUnsignedCharRE.MatchString(vts): 177 | fallthrough 178 | case cUint8tCharRE.MatchString(vts): 179 | doConvert = true 180 | 181 | // Try to use existing uint8 slices and fall back to converting 182 | // and copying if that fails. 183 | case vt.Kind() == reflect.Uint8: 184 | // We need an addressable interface to convert the type 185 | // to a byte slice. However, the reflect package won't 186 | // give us an interface on certain things like 187 | // unexported struct fields in order to enforce 188 | // visibility rules. We use unsafe, when available, to 189 | // bypass these restrictions since this package does not 190 | // mutate the values. 191 | vs := v 192 | if !vs.CanInterface() || !vs.CanAddr() { 193 | vs = unsafeReflectValue(vs) 194 | } 195 | if !UnsafeDisabled { 196 | vs = vs.Slice(0, numEntries) 197 | 198 | // Use the existing uint8 slice if it can be 199 | // type asserted. 200 | iface := vs.Interface() 201 | if slice, ok := iface.([]uint8); ok { 202 | buf = slice 203 | doHexDump = true 204 | break 205 | } 206 | } 207 | 208 | // The underlying data needs to be converted if it can't 209 | // be type asserted to a uint8 slice. 210 | doConvert = true 211 | } 212 | 213 | // Copy and convert the underlying type if needed. 214 | if doConvert && vt.ConvertibleTo(uint8Type) { 215 | // Convert and copy each element into a uint8 byte 216 | // slice. 217 | buf = make([]uint8, numEntries) 218 | for i := 0; i < numEntries; i++ { 219 | vv := v.Index(i) 220 | buf[i] = uint8(vv.Convert(uint8Type).Uint()) 221 | } 222 | doHexDump = true 223 | } 224 | } 225 | 226 | // Hexdump the entire slice as needed. 227 | if doHexDump { 228 | indent := strings.Repeat(d.cs.Indent, d.depth) 229 | str := indent + hex.Dump(buf) 230 | str = strings.Replace(str, "\n", "\n"+indent, -1) 231 | str = strings.TrimRight(str, d.cs.Indent) 232 | d.w.Write([]byte(str)) 233 | return 234 | } 235 | 236 | // Recursively call dump for each item. 237 | for i := 0; i < numEntries; i++ { 238 | d.dump(d.unpackValue(v.Index(i))) 239 | if i < (numEntries - 1) { 240 | d.w.Write(commaNewlineBytes) 241 | } else { 242 | d.w.Write(newlineBytes) 243 | } 244 | } 245 | } 246 | 247 | // dump is the main workhorse for dumping a value. It uses the passed reflect 248 | // value to figure out what kind of object we are dealing with and formats it 249 | // appropriately. It is a recursive function, however circular data structures 250 | // are detected and handled properly. 251 | func (d *dumpState) dump(v reflect.Value) { 252 | // Handle invalid reflect values immediately. 253 | kind := v.Kind() 254 | if kind == reflect.Invalid { 255 | d.w.Write(invalidAngleBytes) 256 | return 257 | } 258 | 259 | // Handle pointers specially. 260 | if kind == reflect.Ptr { 261 | d.indent() 262 | d.dumpPtr(v) 263 | return 264 | } 265 | 266 | // Print type information unless already handled elsewhere. 267 | if !d.ignoreNextType { 268 | d.indent() 269 | d.w.Write(openParenBytes) 270 | d.w.Write([]byte(v.Type().String())) 271 | d.w.Write(closeParenBytes) 272 | d.w.Write(spaceBytes) 273 | } 274 | d.ignoreNextType = false 275 | 276 | // Display length and capacity if the built-in len and cap functions 277 | // work with the value's kind and the len/cap itself is non-zero. 278 | valueLen, valueCap := 0, 0 279 | switch v.Kind() { 280 | case reflect.Array, reflect.Slice, reflect.Chan: 281 | valueLen, valueCap = v.Len(), v.Cap() 282 | case reflect.Map, reflect.String: 283 | valueLen = v.Len() 284 | } 285 | if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { 286 | d.w.Write(openParenBytes) 287 | if valueLen != 0 { 288 | d.w.Write(lenEqualsBytes) 289 | printInt(d.w, int64(valueLen), 10) 290 | } 291 | if !d.cs.DisableCapacities && valueCap != 0 { 292 | if valueLen != 0 { 293 | d.w.Write(spaceBytes) 294 | } 295 | d.w.Write(capEqualsBytes) 296 | printInt(d.w, int64(valueCap), 10) 297 | } 298 | d.w.Write(closeParenBytes) 299 | d.w.Write(spaceBytes) 300 | } 301 | 302 | // Call Stringer/error interfaces if they exist and the handle methods flag 303 | // is enabled 304 | if !d.cs.DisableMethods { 305 | if (kind != reflect.Invalid) && (kind != reflect.Interface) { 306 | if handled := handleMethods(d.cs, d.w, v); handled { 307 | return 308 | } 309 | } 310 | } 311 | 312 | switch kind { 313 | case reflect.Invalid: 314 | // Do nothing. We should never get here since invalid has already 315 | // been handled above. 316 | 317 | case reflect.Bool: 318 | printBool(d.w, v.Bool()) 319 | 320 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 321 | printInt(d.w, v.Int(), 10) 322 | 323 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 324 | printUint(d.w, v.Uint(), 10) 325 | 326 | case reflect.Float32: 327 | printFloat(d.w, v.Float(), 32) 328 | 329 | case reflect.Float64: 330 | printFloat(d.w, v.Float(), 64) 331 | 332 | case reflect.Complex64: 333 | printComplex(d.w, v.Complex(), 32) 334 | 335 | case reflect.Complex128: 336 | printComplex(d.w, v.Complex(), 64) 337 | 338 | case reflect.Slice: 339 | if v.IsNil() { 340 | d.w.Write(nilAngleBytes) 341 | break 342 | } 343 | fallthrough 344 | 345 | case reflect.Array: 346 | d.w.Write(openBraceNewlineBytes) 347 | d.depth++ 348 | if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { 349 | d.indent() 350 | d.w.Write(maxNewlineBytes) 351 | } else { 352 | d.dumpSlice(v) 353 | } 354 | d.depth-- 355 | d.indent() 356 | d.w.Write(closeBraceBytes) 357 | 358 | case reflect.String: 359 | d.w.Write([]byte(strconv.Quote(v.String()))) 360 | 361 | case reflect.Interface: 362 | // The only time we should get here is for nil interfaces due to 363 | // unpackValue calls. 364 | if v.IsNil() { 365 | d.w.Write(nilAngleBytes) 366 | } 367 | 368 | case reflect.Ptr: 369 | // Do nothing. We should never get here since pointers have already 370 | // been handled above. 371 | 372 | case reflect.Map: 373 | // nil maps should be indicated as different than empty maps 374 | if v.IsNil() { 375 | d.w.Write(nilAngleBytes) 376 | break 377 | } 378 | 379 | d.w.Write(openBraceNewlineBytes) 380 | d.depth++ 381 | if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { 382 | d.indent() 383 | d.w.Write(maxNewlineBytes) 384 | } else { 385 | numEntries := v.Len() 386 | keys := v.MapKeys() 387 | if d.cs.SortKeys { 388 | sortValues(keys, d.cs) 389 | } 390 | for i, key := range keys { 391 | d.dump(d.unpackValue(key)) 392 | d.w.Write(colonSpaceBytes) 393 | d.ignoreNextIndent = true 394 | d.dump(d.unpackValue(v.MapIndex(key))) 395 | if i < (numEntries - 1) { 396 | d.w.Write(commaNewlineBytes) 397 | } else { 398 | d.w.Write(newlineBytes) 399 | } 400 | } 401 | } 402 | d.depth-- 403 | d.indent() 404 | d.w.Write(closeBraceBytes) 405 | 406 | case reflect.Struct: 407 | d.w.Write(openBraceNewlineBytes) 408 | d.depth++ 409 | if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { 410 | d.indent() 411 | d.w.Write(maxNewlineBytes) 412 | } else { 413 | vt := v.Type() 414 | numFields := v.NumField() 415 | for i := 0; i < numFields; i++ { 416 | d.indent() 417 | vtf := vt.Field(i) 418 | d.w.Write([]byte(vtf.Name)) 419 | d.w.Write(colonSpaceBytes) 420 | d.ignoreNextIndent = true 421 | d.dump(d.unpackValue(v.Field(i))) 422 | if i < (numFields - 1) { 423 | d.w.Write(commaNewlineBytes) 424 | } else { 425 | d.w.Write(newlineBytes) 426 | } 427 | } 428 | } 429 | d.depth-- 430 | d.indent() 431 | d.w.Write(closeBraceBytes) 432 | 433 | case reflect.Uintptr: 434 | printHexPtr(d.w, uintptr(v.Uint())) 435 | 436 | case reflect.UnsafePointer, reflect.Chan, reflect.Func: 437 | printHexPtr(d.w, v.Pointer()) 438 | 439 | // There were not any other types at the time this code was written, but 440 | // fall back to letting the default fmt package handle it in case any new 441 | // types are added. 442 | default: 443 | if v.CanInterface() { 444 | fmt.Fprintf(d.w, "%v", v.Interface()) 445 | } else { 446 | fmt.Fprintf(d.w, "%v", v.String()) 447 | } 448 | } 449 | } 450 | 451 | // fdump is a helper function to consolidate the logic from the various public 452 | // methods which take varying writers and config states. 453 | func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { 454 | for _, arg := range a { 455 | if arg == nil { 456 | w.Write(interfaceBytes) 457 | w.Write(spaceBytes) 458 | w.Write(nilAngleBytes) 459 | w.Write(newlineBytes) 460 | continue 461 | } 462 | 463 | d := dumpState{w: w, cs: cs} 464 | d.pointers = make(map[uintptr]int) 465 | d.dump(reflect.ValueOf(arg)) 466 | d.w.Write(newlineBytes) 467 | } 468 | } 469 | 470 | // Fdump formats and displays the passed arguments to io.Writer w. It formats 471 | // exactly the same as Dump. 472 | func Fdump(w io.Writer, a ...interface{}) { 473 | fdump(&Config, w, a...) 474 | } 475 | 476 | // Sdump returns a string with the passed arguments formatted exactly the same 477 | // as Dump. 478 | func Sdump(a ...interface{}) string { 479 | var buf bytes.Buffer 480 | fdump(&Config, &buf, a...) 481 | return buf.String() 482 | } 483 | 484 | /* 485 | Dump displays the passed parameters to standard out with newlines, customizable 486 | indentation, and additional debug information such as complete types and all 487 | pointer addresses used to indirect to the final value. It provides the 488 | following features over the built-in printing facilities provided by the fmt 489 | package: 490 | 491 | * Pointers are dereferenced and followed 492 | * Circular data structures are detected and handled properly 493 | * Custom Stringer/error interfaces are optionally invoked, including 494 | on unexported types 495 | * Custom types which only implement the Stringer/error interfaces via 496 | a pointer receiver are optionally invoked when passing non-pointer 497 | variables 498 | * Byte arrays and slices are dumped like the hexdump -C command which 499 | includes offsets, byte values in hex, and ASCII output 500 | 501 | The configuration options are controlled by an exported package global, 502 | spew.Config. See ConfigState for options documentation. 503 | 504 | See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to 505 | get the formatted result as a string. 506 | */ 507 | func Dump(a ...interface{}) { 508 | fdump(&Config, os.Stdout, a...) 509 | } 510 | --------------------------------------------------------------------------------