├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── build ├── TitleCase.pl ├── generate.sh ├── skeleton_model.go.tpl └── skeleton_service.go.tpl ├── doc.go ├── examples └── towerapi.go ├── model ├── activity_stream.go ├── ad_hoc_commands.go ├── config.go ├── credentials.go ├── dashboard.go ├── inventory_scripts.go ├── inventory_sources.go ├── job_events.go ├── job_templates.go ├── jobs.go ├── labels.go ├── me.go ├── notification_templates.go ├── notifications.go ├── ping.go ├── projects.go ├── roles.go ├── schedules.go ├── system_job_templates.go ├── system_jobs.go ├── teams.go ├── unified_job_templates.go ├── unified_jobs.go └── users.go └── towerapi ├── authtoken ├── authtoken.go ├── authtoken_model.go └── authtoken_test.go ├── credentials ├── credentials.go └── credentials_struct.go ├── doc.go ├── errors └── error.go ├── groups ├── groups.go └── groups_struct.go ├── hosts ├── hosts.go └── hosts_struct.go ├── inventories ├── inventories.go └── inventories_struct.go ├── job_templates ├── job_templates.go ├── job_templates_struct.go └── job_templates_test.go ├── organizations ├── organizations.go └── organizations_struct.go ├── params └── params.go ├── projects ├── projects.go └── projects_struct.go ├── towerapi.go └── towerapi_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/go,intellij,vim 3 | 4 | ### Go ### 5 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 6 | *.o 7 | *.a 8 | *.so 9 | 10 | # Folders 11 | _obj 12 | _test 13 | 14 | # Architecture specific extensions/prefixes 15 | *.[568vq] 16 | [568vq].out 17 | 18 | *.cgo1.go 19 | *.cgo2.c 20 | _cgo_defun.c 21 | _cgo_gotypes.go 22 | _cgo_export.* 23 | 24 | _testmain.go 25 | 26 | *.exe 27 | *.test 28 | *.prof 29 | 30 | # Output of the go coverage tool, specifically when used with LiteIDE 31 | *.out 32 | 33 | 34 | ### Intellij ### 35 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 36 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 37 | 38 | # User-specific stuff: 39 | .idea/workspace.xml 40 | .idea/tasks.xml 41 | .idea/dictionaries 42 | .idea/vcs.xml 43 | .idea/jsLibraryMappings.xml 44 | 45 | # Sensitive or high-churn files: 46 | .idea/dataSources.ids 47 | .idea/dataSources.xml 48 | .idea/dataSources.local.xml 49 | .idea/sqlDataSources.xml 50 | .idea/dynamic.xml 51 | .idea/uiDesigner.xml 52 | # Gradle: 53 | .idea/gradle.xml 54 | .idea/libraries/ 55 | .idea/watcherTasks.xml 56 | 57 | # Mongo Explorer plugin: 58 | .idea/mongoSettings.xml 59 | 60 | ## File-based project format: 61 | *.iws 62 | 63 | ## Plugin-specific files: 64 | 65 | # IntelliJ 66 | /out/ 67 | *.iml 68 | .idea/* 69 | # mpeltonen/sbt-idea plugin 70 | .idea_modules/ 71 | 72 | # JIRA plugin 73 | atlassian-ide-plugin.xml 74 | 75 | # Crashlytics plugin (for Android Studio and IntelliJ) 76 | com_crashlytics_export_strings.xml 77 | crashlytics.properties 78 | crashlytics-build.properties 79 | fabric.properties 80 | 81 | ### Intellij Patch ### 82 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 83 | 84 | # *.iml 85 | # modules.xml 86 | # .idea/misc.xml 87 | # *.ipr 88 | 89 | 90 | ### Vim ### 91 | # swap 92 | [._]*.s[a-w][a-z] 93 | [._]s[a-w][a-z] 94 | # session 95 | Session.vim 96 | # temporary 97 | .netrwhist 98 | *~ 99 | # auto-generated tag files 100 | tags 101 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you submit a pull request, please keep the following guidelines in mind: 4 | 5 | 1. Code should be `go fmt` compliant. 6 | 2. Types, structs and funcs should be documented. 7 | 3. Tests pass. 8 | 9 | ## Getting set up 10 | 11 | Assuming your `$GOPATH` is set up according to your desires, run: 12 | 13 | ```sh 14 | go get github.com/digitalocean/godo 15 | ``` 16 | 17 | ## Running tests 18 | 19 | When working on code in this repository, tests can be run via: 20 | 21 | ```sh 22 | go test . 23 | ``` 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2016 The godo AUTHORS. All rights reserved. 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included 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 OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | ====================== 25 | Portions of the client are based on code at: 26 | https://github.com/google/go-github/ 27 | 28 | Copyright (c) 2013 The go-github AUTHORS. All rights reserved. 29 | 30 | Redistribution and use in source and binary forms, with or without 31 | modification, are permitted provided that the following conditions are 32 | met: 33 | 34 | * Redistributions of source code must retain the above copyright 35 | notice, this list of conditions and the following disclaimer. 36 | * Redistributions in binary form must reproduce the above 37 | copyright notice, this list of conditions and the following disclaimer 38 | in the documentation and/or other materials provided with the 39 | distribution. 40 | * Neither the name of Google Inc. nor the names of its 41 | contributors may be used to endorse or promote products derived from 42 | this software without specific prior written permission. 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 45 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 46 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 47 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 48 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 49 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 50 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 54 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/mpeter/go-towerapi.svg)](https://travis-ci.org/mpeter/go-towerapi) 2 | 3 | # TowerAPI 4 | 5 | WORK IN PROGRESS 6 | 7 | TowerAPI is a Go client library for accessing the Ansible Tower V1 API. 8 | 9 | You can view the client API docs here: [http://godoc.org/github.com/mpeter/go-towerapi](http://godoc.org/github.com/mpeter/go-towerapi) 10 | 11 | You can view Ansible Tower API docs here: [http://docs.ansible.com/ansible-tower/latest/html/towerapi/index.html](http://docs.ansible.com/ansible-tower/latest/html/towerapi/index.html) 12 | 13 | ## Usage 14 | 15 | ```go 16 | import "github.com/mpeter/go-towerapi" 17 | ``` 18 | 19 | Create a new Ansible Tower client, then use the exposed services to 20 | access different parts of the Ansible Tower API. 21 | 22 | ### Authentication 23 | 24 | Currently, Basic Auth is the only method of 25 | authenticating with the API. You can manage your users 26 | inside the Ansible Tower Control GUI. 27 | 28 | You can then use your token to create a new client: 29 | 30 | ```go 31 | import ( 32 | "net/http" 33 | "github.com/mpeter/go-towerapi/towerapi" 34 | ) 35 | 36 | type Config struct { 37 | Endpoint string 38 | Username string 39 | Password string 40 | } 41 | 42 | func (c *Config) NewClient() (*towerapi.Client, error) { 43 | config := &towerapi.ClientConfig{ 44 | Endpoint = c.Endpoint, 45 | Username = c.Username, 46 | Password = c.Password, 47 | } 48 | 49 | return towerapi.NewClient(http.DefaultClient, config) 50 | } 51 | 52 | ``` 53 | ## Examples 54 | 55 | To create a new Organization: 56 | 57 | ```go 58 | config := new(towerapi.ClientConfig) 59 | config.Endpoint = c.Endpoint 60 | config.Password = c.Password 61 | config.Username = c.Username 62 | 63 | //return towerapi.NewClient(http.DefaultClient, config) 64 | 65 | api, err := towerapi.NewClient(http.DefaultClient, config) 66 | request := &organizations.Request{ 67 | Name: "Org Name", 68 | Description: "Org Description", 69 | } 70 | org, resp, err := api.Organizations.Create(request) 71 | if err != nil { 72 | fmt.Errorf("ERROR: Organization.Create: %v", err) 73 | } 74 | fmt.Printf("Organization Struct: %v", org) 75 | fmt.Printf("Organization Response: %v", resp) 76 | ``` 77 | 78 | ### Pagination 79 | 80 | If a list of items is paginated by the API, you must request pages individually. For example, to fetch all Droplets: 81 | 82 | TBD 83 | 84 | ## Versioning 85 | 86 | TBD 87 | 88 | ## Documentation 89 | For details on all the functionality in this library, see the [GoDoc](http://godoc.org/github.com/mpeter/go-towerapi) documentation. 90 | 91 | 92 | ## Contributing 93 | 94 | We love pull requests! Please see the [contribution guidelines](CONTRIBUTING.md). 95 | -------------------------------------------------------------------------------- /build/TitleCase.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # This filter changes all words to Title Caps, and attempts to be clever 4 | # about *un*capitalizing small words like a/an/the in the input. 5 | # 6 | # The list of "small words" which are not capped comes from 7 | # the New York Times Manual of Style, plus 'vs' and 'v'. 8 | # 9 | # 10 May 2008 10 | # Original version by John Gruber: 11 | # http://daringfireball.net/2008/05/title_case 12 | # 13 | # 28 July 2008 14 | # Re-written and much improved by Aristotle Pagaltzis: 15 | # http://plasmasturm.org/code/titlecase/ 16 | # 17 | # Full change log at __END__. 18 | # 19 | # License: http://www.opensource.org/licenses/mit-license.php 20 | # 21 | 22 | 23 | use strict; 24 | use warnings; 25 | use utf8; 26 | use open qw( :encoding(UTF-8) :std ); 27 | 28 | 29 | my @small_words = qw( (? ) { 35 | s{\A\s+}{}, s{\s+\z}{}; 36 | 37 | $_ = lc $_ if not /[[:lower:]]/; 38 | 39 | s{ 40 | \b (_*) (?: 41 | ( (?<=[ ][/\\]) [[:alpha:]]+ [-_[:alpha:]/\\]+ | # file path or 42 | [-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ $apos ) # URL, domain, or email 43 | | 44 | ( (?i: $small_re ) $apos ) # or small word (case-insensitive) 45 | | 46 | ( [[:alpha:]] [[:lower:]'’()\[\]{}]* $apos ) # or word w/o internal caps 47 | | 48 | ( [[:alpha:]] [[:alpha:]'’()\[\]{}]* $apos ) # or some other word 49 | ) (_*) \b 50 | }{ 51 | $1 . ( 52 | defined $2 ? $2 # preserve URL, domain, or email 53 | : defined $3 ? "\L$3" # lowercase small word 54 | : defined $4 ? "\u\L$4" # capitalize word w/o internal caps 55 | : $5 # preserve other kinds of word 56 | ) . $6 57 | }xeg; 58 | 59 | 60 | # Exceptions for small words: capitalize at start and end of title 61 | s{ 62 | ( \A [[:punct:]]* # start of title... 63 | | [:.;?!][ ]+ # or of subsentence... 64 | | [ ]['"“‘(\[][ ]* ) # or of inserted subphrase... 65 | ( $small_re ) \b # ... followed by small word 66 | }{$1\u\L$2}xig; 67 | 68 | s{ 69 | \b ( $small_re ) # small word... 70 | (?= [[:punct:]]* \Z # ... at the end of the title... 71 | | ['"’”)\]] [ ] ) # ... or of an inserted subphrase? 72 | }{\u\L$1}xig; 73 | 74 | # Exceptions for small words in hyphenated compound words 75 | ## e.g. "in-flight" -> In-Flight 76 | s{ 77 | \b 78 | (? "Stand-In" (Stand is already capped at this point) 84 | s{ 85 | \b 86 | (?&2 ; exit 1 ; fi 15 | echo "$OPTS" 16 | eval set -- "$OPTS" 17 | 18 | TOWER_USERNAME=admin 19 | TOWER_PASSWORD=TX5KmCUKM5Sp 20 | TOWER_ENDPOINT=http://ansible-tower/api/v1 21 | 22 | while true; do 23 | case "$1" in 24 | -e | --endpoint ) TOWER_ENDPOINT=true; shift ;; 25 | -u | --username ) TOWER_USERNAME=true; shift ;; 26 | -p | --password ) TOWER_PASSWORD=true; shift ;; 27 | -- ) shift; break ;; 28 | * ) break ;; 29 | esac 30 | done 31 | 32 | echo TOWER_ENDPOINT=$TOWER_ENDPOINT 33 | echo TOWER_USERNAME=$TOWER_USERNAME 34 | echo TOWER_PASSWORD=$TOWER_PASSWORD 35 | 36 | # AuthToken 37 | LIST_TYPES=(Activity_Stream Dashboard Ping Config Me Ad_Hoc_Commands 38 | Organizations Users Projects Teams Credentials Inventories Inventory_Scripts 39 | Inventory_Sources Groups Hosts Job_Templates Jobs Job_Events 40 | System_Job_Templates System_Jobs Schedules Roles Notification_Templates 41 | Notifications Labels Unified_Job_Templates Unified_Jobs ) 42 | 43 | #LIST_TYPES=( Dashboard ) 44 | 45 | # Save the pwd before we run anything 46 | PRE_PWD=`pwd` 47 | 48 | # Determine the build script's actual directory, following symlinks 49 | SOURCE="${BASH_SOURCE[0]}" 50 | while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done 51 | BUILD_DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)" 52 | 53 | # Derive the project name from the directory 54 | PROJECT="$(basename $BUILD_DIR)" 55 | 56 | base_cmd="http --session=`date "+%Y%m%d"` --auth $TOWER_USERNAME:$TOWER_PASSWORD --body --pretty=format http://ansible-tower" 57 | 58 | for t in ${LIST_TYPES[*]}; 59 | do 60 | name_uri=`echo "$t" | awk '{ print tolower($1) }'` 61 | name_struct=`echo $t | sed 's/_//g'` 62 | name_lcamel=`echo $name_struct | perl -ne 'print lcfirst($_);'` 63 | 64 | echo "Generating model for $name_struct" 65 | # Generate JSON Example for LIST type 66 | entity_list_file="../towerapi/model/${name_uri}.json" 67 | entity_list_json=`$base_cmd/api/v1/$name_uri/?page_size=1\&page=1\&order_by=id | jq .` 68 | # re-create the output file 69 | rm -f $entity_list_file && echo $entity_list_json > $entity_list_file 70 | # Derive the URL and type of the result entry in list 71 | entity_url=`jq 'try .results[0].url catch ""' $entity_list_file | tr -d '"'` 72 | entity_type=`jq 'try .results[0].type catch ""' $entity_list_file | tr -d '"'` 73 | # Derive struct name 74 | entity_struct=`echo $entity_type | sed 's/_/ /g' | perl TitleCase.pl | sed 's/ //g'` 75 | # Default null values to string 76 | sed -i '' -e "s/null/\"string\"/g" $entity_list_file 77 | 78 | # Generate JSON Example for CRUD type based on List type 79 | entity_go_file="../towerapi/model/${name_uri}.go" 80 | rm -f $entity_go_file 81 | if [[ "${entity_type}" == "null" ]]; then 82 | gojson -input $entity_list_file -name ${name_struct} -pkg towerapi -o $entity_go_file 83 | else 84 | jq 'del(.results[])' $entity_list_file | gojson -name ${name_struct} -pkg towerapi | sed -e "s/\[\]interface{}/\[\]${entity_struct}/" > $entity_go_file 85 | $base_cmd$entity_url | jq . | sed -e "s/null/\"string\"/g" | gojson -name $entity_struct -pkg towerapi | sed -e 's/package towerapi//' >> $entity_go_file 86 | fi 87 | done 88 | 89 | -------------------------------------------------------------------------------- /build/skeleton_model.go.tpl: -------------------------------------------------------------------------------- 1 | 2 | type Credentials struct { 3 | Count int `json:"count"` 4 | Next interface{} `json:"next"` 5 | Previous interface{} `json:"previous"` 6 | Results []Credential `json:results` 7 | } 8 | -------------------------------------------------------------------------------- /build/skeleton_service.go.tpl: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | import ( 4 | "github.com/dghubble/sling" 5 | ) 6 | 7 | const {{name_lcamel}}BasePath = "/{{name_uri}}" 8 | 9 | type {{name_struct}}Service struct { 10 | sling *sling.Sling 11 | } 12 | 13 | // New{{name_struct}} creates a new instance of this service 14 | func New{{name_struct}}Service(sling *sling.Sling) *{{name_struct}}Service { 15 | return &{{name_struct}}Service { 16 | sling: sling.Path({{name_lcamel}}BasePath), 17 | } 18 | } 19 | 20 | // List all {{name_uri}} 21 | func (s *{{name_struct}}Service) List() ([]{{name_struct}}, *Response, error) { 22 | root := new({{name_struct}}) 23 | errorResponse := new(ErrorResponse) 24 | resp, err := s.sling.New().Get("/").Receive(root, errorResponse) 25 | return root.Results, resp, err 26 | } 27 | 28 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // TODO 2 | package go_towerapi 3 | -------------------------------------------------------------------------------- /examples/towerapi.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "strconv" 8 | 9 | "github.com/mpeter/go-towerapi/towerapi" 10 | "github.com/mpeter/go-towerapi/towerapi/inventories" 11 | ) 12 | 13 | func main() { 14 | endpoint := os.Getenv("TOWER_ENDPOINT") 15 | username := os.Getenv("TOWER_USERNAME") 16 | password := os.Getenv("TOWER_PASSWORD") 17 | 18 | fmt.Println("Using these values:") 19 | fmt.Println("endpoint:", endpoint) 20 | fmt.Println("username:", username) 21 | fmt.Println("password:", password) 22 | 23 | if len(endpoint) == 0 || len(username) == 0 || len(password) == 0 { 24 | log.Fatal("Environment variable(s) not set\n") 25 | } 26 | config := &towerapi.Config{ 27 | Endpoint: endpoint, 28 | Username: username, 29 | Password: password, 30 | } 31 | client, err := towerapi.NewClient(config) 32 | 33 | if err != nil { 34 | log.Fatalf("towerapi.NewClient: %s", err) 35 | } 36 | org := 1 37 | anInventory := &inventories.Request{ 38 | Name: "aname15", 39 | Description: "asdf", 40 | Organization: &org, 41 | Variables: "", 42 | } 43 | inventory, err := client.Inventories.Create(anInventory) 44 | if err != nil { 45 | fmt.Errorf("Inventories.Create returned error: %v", err) 46 | } 47 | log.Printf("Inventories.Create Inventory: %v", inventory) 48 | 49 | inventory1, err := client.Inventories.GetByID(strconv.Itoa(inventory.ID)) 50 | log.Printf("Inventory ID: %d", inventory1.ID) 51 | 52 | name := inventory1.Name 53 | inventory2, err := client.Inventories.GetByName(name) 54 | log.Printf("Inventory Name: %s", inventory2.Name) 55 | 56 | anInventory.Description = "changed description" 57 | inventory3, err := client.Inventories.Update(anInventory) 58 | log.Printf("Inventory Description: %s", inventory3.Description) 59 | 60 | client.Inventories.Delete(strconv.Itoa(inventory3.ID)) 61 | inventory4, err := client.Inventories.Create(anInventory) 62 | log.Printf("Inventory Name (After Delete): %s", inventory4.Name) 63 | 64 | // Cleanup 65 | client.Inventories.Delete(strconv.Itoa(inventory4.ID)) 66 | 67 | } 68 | -------------------------------------------------------------------------------- /model/activity_stream.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type ActivityStream struct { 4 | Detail string `json:"detail"` 5 | } 6 | -------------------------------------------------------------------------------- /model/ad_hoc_commands.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type AdHocCommands struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []AdHocCommand `json:"results"` 8 | } 9 | 10 | type AdHocCommand struct { 11 | BecomeEnabled bool `json:"become_enabled"` 12 | Created string `json:"created"` 13 | Credential int `json:"credential"` 14 | Elapsed float64 `json:"elapsed"` 15 | ExtraVars string `json:"extra_vars"` 16 | Failed bool `json:"failed"` 17 | Finished string `json:"finished"` 18 | Forks int `json:"forks"` 19 | ID int `json:"id"` 20 | Inventory int `json:"inventory"` 21 | JobArgs string `json:"job_args"` 22 | JobCwd string `json:"job_cwd"` 23 | JobEnv struct { 24 | ADHOCCOMMANDID string `json:"AD_HOC_COMMAND_ID"` 25 | ANSIBLECALLBACKPLUGINS string `json:"ANSIBLE_CALLBACK_PLUGINS"` 26 | ANSIBLEFORCECOLOR string `json:"ANSIBLE_FORCE_COLOR"` 27 | ANSIBLEHOSTKEYCHECKING string `json:"ANSIBLE_HOST_KEY_CHECKING"` 28 | ANSIBLELOADCALLBACKPLUGINS string `json:"ANSIBLE_LOAD_CALLBACK_PLUGINS"` 29 | ANSIBLEPARAMIKORECORDHOSTKEYS string `json:"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS"` 30 | ANSIBLESFTPBATCHMODE string `json:"ANSIBLE_SFTP_BATCH_MODE"` 31 | ANSIBLESSHARGS string `json:"ANSIBLE_SSH_ARGS"` 32 | ANSIBLEUSEVENV string `json:"ANSIBLE_USE_VENV"` 33 | ANSIBLEVENVPATH string `json:"ANSIBLE_VENV_PATH"` 34 | CALLBACKCONSUMERPORT string `json:"CALLBACK_CONSUMER_PORT"` 35 | CELERYLOADER string `json:"CELERY_LOADER"` 36 | CELERYLOGFILE string `json:"CELERY_LOG_FILE"` 37 | CELERYLOGLEVEL string `json:"CELERY_LOG_LEVEL"` 38 | CELERYLOGREDIRECT string `json:"CELERY_LOG_REDIRECT"` 39 | CELERYLOGREDIRECTLEVEL string `json:"CELERY_LOG_REDIRECT_LEVEL"` 40 | DJANGOLIVETESTSERVERADDRESS string `json:"DJANGO_LIVE_TEST_SERVER_ADDRESS"` 41 | DJANGOPROJECTDIR string `json:"DJANGO_PROJECT_DIR"` 42 | DJANGOSETTINGSMODULE string `json:"DJANGO_SETTINGS_MODULE"` 43 | HOME string `json:"HOME"` 44 | INVENTORYHOSTVARS string `json:"INVENTORY_HOSTVARS"` 45 | INVENTORYID string `json:"INVENTORY_ID"` 46 | LANG string `json:"LANG"` 47 | PATH string `json:"PATH"` 48 | PROOTTMPDIR string `json:"PROOT_TMP_DIR"` 49 | PS1 string `json:"PS1"` 50 | PWD string `json:"PWD"` 51 | PYTHONPATH string `json:"PYTHONPATH"` 52 | RESTAPITOKEN string `json:"REST_API_TOKEN"` 53 | RESTAPIURL string `json:"REST_API_URL"` 54 | SHLVL string `json:"SHLVL"` 55 | SUPERVISORENABLED string `json:"SUPERVISOR_ENABLED"` 56 | SUPERVISORGROUPNAME string `json:"SUPERVISOR_GROUP_NAME"` 57 | SUPERVISORPROCESSNAME string `json:"SUPERVISOR_PROCESS_NAME"` 58 | SUPERVISORSERVERURL string `json:"SUPERVISOR_SERVER_URL"` 59 | TZ string `json:"TZ"` 60 | USER string `json:"USER"` 61 | VIRTUALENV string `json:"VIRTUAL_ENV"` 62 | MPFORKLOGFILE string `json:"_MP_FORK_LOGFILE_"` 63 | MPFORKLOGFORMAT string `json:"_MP_FORK_LOGFORMAT_"` 64 | MPFORKLOGLEVEL string `json:"_MP_FORK_LOGLEVEL_"` 65 | } `json:"job_env"` 66 | JobExplanation string `json:"job_explanation"` 67 | JobType string `json:"job_type"` 68 | LaunchType string `json:"launch_type"` 69 | Limit string `json:"limit"` 70 | Modified string `json:"modified"` 71 | ModuleArgs string `json:"module_args"` 72 | ModuleName string `json:"module_name"` 73 | Name string `json:"name"` 74 | Related struct { 75 | ActivityStream string `json:"activity_stream"` 76 | Cancel string `json:"cancel"` 77 | CreatedBy string `json:"created_by"` 78 | Credential string `json:"credential"` 79 | Events string `json:"events"` 80 | Inventory string `json:"inventory"` 81 | Relaunch string `json:"relaunch"` 82 | Stdout string `json:"stdout"` 83 | } `json:"related"` 84 | ResultStdout string `json:"result_stdout"` 85 | ResultTraceback string `json:"result_traceback"` 86 | Started string `json:"started"` 87 | Status string `json:"status"` 88 | SummaryFields struct { 89 | CreatedBy struct { 90 | FirstName string `json:"first_name"` 91 | ID int `json:"id"` 92 | LastName string `json:"last_name"` 93 | Username string `json:"username"` 94 | } `json:"created_by"` 95 | Credential struct { 96 | Cloud bool `json:"cloud"` 97 | Description string `json:"description"` 98 | ID int `json:"id"` 99 | Kind string `json:"kind"` 100 | Name string `json:"name"` 101 | } `json:"credential"` 102 | Inventory struct { 103 | Description string `json:"description"` 104 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 105 | HasActiveFailures bool `json:"has_active_failures"` 106 | HasInventorySources bool `json:"has_inventory_sources"` 107 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 108 | ID int `json:"id"` 109 | InventorySourcesWithFailures int `json:"inventory_sources_with_failures"` 110 | Name string `json:"name"` 111 | TotalGroups int `json:"total_groups"` 112 | TotalHosts int `json:"total_hosts"` 113 | TotalInventorySources int `json:"total_inventory_sources"` 114 | } `json:"inventory"` 115 | } `json:"summary_fields"` 116 | Type string `json:"type"` 117 | URL string `json:"url"` 118 | Verbosity int `json:"verbosity"` 119 | } 120 | -------------------------------------------------------------------------------- /model/config.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Config struct { 4 | AnalyticsStatus string `json:"analytics_status"` 5 | AnsibleVersion string `json:"ansible_version"` 6 | Eula string `json:"eula"` 7 | LicenseInfo struct { 8 | AvailableInstances int `json:"available_instances"` 9 | CompanyName string `json:"company_name"` 10 | Compliant bool `json:"compliant"` 11 | ContactEmail string `json:"contact_email"` 12 | ContactName string `json:"contact_name"` 13 | CurrentInstances int `json:"current_instances"` 14 | DateExpired bool `json:"date_expired"` 15 | DateWarning bool `json:"date_warning"` 16 | DeploymentID string `json:"deployment_id"` 17 | Features struct { 18 | ActivityStreams bool `json:"activity_streams"` 19 | EnterpriseAuth bool `json:"enterprise_auth"` 20 | Ha bool `json:"ha"` 21 | Ldap bool `json:"ldap"` 22 | MultipleOrganizations bool `json:"multiple_organizations"` 23 | Rebranding bool `json:"rebranding"` 24 | Surveys bool `json:"surveys"` 25 | SystemTracking bool `json:"system_tracking"` 26 | } `json:"features"` 27 | FreeInstances int `json:"free_instances"` 28 | GracePeriodRemaining int `json:"grace_period_remaining"` 29 | Hostname string `json:"hostname"` 30 | InstanceCount int `json:"instance_count"` 31 | LicenseDate int `json:"license_date"` 32 | LicenseKey string `json:"license_key"` 33 | LicenseType string `json:"license_type"` 34 | SubscriptionName string `json:"subscription_name"` 35 | TimeRemaining int `json:"time_remaining"` 36 | ValidKey bool `json:"valid_key"` 37 | } `json:"license_info"` 38 | ProjectBaseDir string `json:"project_base_dir"` 39 | ProjectLocalPaths []interface{} `json:"project_local_paths"` 40 | TimeZone string `json:"time_zone"` 41 | Version string `json:"version"` 42 | } 43 | -------------------------------------------------------------------------------- /model/credentials.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Credentials struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []Credential `json:"results"` 8 | } 9 | 10 | type Credential struct { 11 | Authorize bool `json:"authorize"` 12 | AuthorizePassword string `json:"authorize_password"` 13 | BecomeMethod string `json:"become_method"` 14 | BecomePassword string `json:"become_password"` 15 | BecomeUsername string `json:"become_username"` 16 | Client string `json:"client"` 17 | Cloud bool `json:"cloud"` 18 | Created string `json:"created"` 19 | Description string `json:"description"` 20 | Domain string `json:"domain"` 21 | Host string `json:"host"` 22 | ID int `json:"id"` 23 | Kind string `json:"kind"` 24 | Modified string `json:"modified"` 25 | Name string `json:"name"` 26 | Organization int `json:"organization"` 27 | Password string `json:"password"` 28 | Project string `json:"project"` 29 | Related struct { 30 | AccessList string `json:"access_list"` 31 | ActivityStream string `json:"activity_stream"` 32 | CreatedBy string `json:"created_by"` 33 | ModifiedBy string `json:"modified_by"` 34 | ObjectRoles string `json:"object_roles"` 35 | Organization string `json:"organization"` 36 | OwnerTeams string `json:"owner_teams"` 37 | OwnerUsers string `json:"owner_users"` 38 | } `json:"related"` 39 | Secret string `json:"secret"` 40 | SecurityToken string `json:"security_token"` 41 | SSHKeyData string `json:"ssh_key_data"` 42 | SSHKeyUnlock string `json:"ssh_key_unlock"` 43 | Subscription string `json:"subscription"` 44 | SummaryFields struct { 45 | CreatedBy struct { 46 | FirstName string `json:"first_name"` 47 | ID int `json:"id"` 48 | LastName string `json:"last_name"` 49 | Username string `json:"username"` 50 | } `json:"created_by"` 51 | Host struct{} `json:"host"` 52 | ModifiedBy struct { 53 | FirstName string `json:"first_name"` 54 | ID int `json:"id"` 55 | LastName string `json:"last_name"` 56 | Username string `json:"username"` 57 | } `json:"modified_by"` 58 | ObjectRoles struct { 59 | AdminRole struct { 60 | Description string `json:"description"` 61 | ID int `json:"id"` 62 | Name string `json:"name"` 63 | } `json:"admin_role"` 64 | ReadRole struct { 65 | Description string `json:"description"` 66 | ID int `json:"id"` 67 | Name string `json:"name"` 68 | } `json:"read_role"` 69 | UseRole struct { 70 | Description string `json:"description"` 71 | ID int `json:"id"` 72 | Name string `json:"name"` 73 | } `json:"use_role"` 74 | } `json:"object_roles"` 75 | Organization struct { 76 | Description string `json:"description"` 77 | ID int `json:"id"` 78 | Name string `json:"name"` 79 | } `json:"organization"` 80 | Owners []struct { 81 | Description string `json:"description"` 82 | ID int `json:"id"` 83 | Name string `json:"name"` 84 | Type string `json:"type"` 85 | URL string `json:"url"` 86 | } `json:"owners"` 87 | Project struct{} `json:"project"` 88 | } `json:"summary_fields"` 89 | Tenant string `json:"tenant"` 90 | Type string `json:"type"` 91 | URL string `json:"url"` 92 | Username string `json:"username"` 93 | VaultPassword string `json:"vault_password"` 94 | } 95 | -------------------------------------------------------------------------------- /model/dashboard.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Dashboard struct { 4 | Credentials struct { 5 | Total int `json:"total"` 6 | URL string `json:"url"` 7 | } `json:"credentials"` 8 | Groups struct { 9 | FailuresURL string `json:"failures_url"` 10 | InventoryFailed int `json:"inventory_failed"` 11 | JobFailed int `json:"job_failed"` 12 | Total int `json:"total"` 13 | URL string `json:"url"` 14 | } `json:"groups"` 15 | Hosts struct { 16 | Failed int `json:"failed"` 17 | FailuresURL string `json:"failures_url"` 18 | Total int `json:"total"` 19 | URL string `json:"url"` 20 | } `json:"hosts"` 21 | Inventories struct { 22 | InventoryFailed int `json:"inventory_failed"` 23 | JobFailed int `json:"job_failed"` 24 | Total int `json:"total"` 25 | TotalWithInventorySource int `json:"total_with_inventory_source"` 26 | URL string `json:"url"` 27 | } `json:"inventories"` 28 | InventorySources struct { 29 | Ec2 struct { 30 | Failed int `json:"failed"` 31 | FailuresURL string `json:"failures_url"` 32 | Label string `json:"label"` 33 | Total int `json:"total"` 34 | URL string `json:"url"` 35 | } `json:"ec2"` 36 | Rax struct { 37 | Failed int `json:"failed"` 38 | FailuresURL string `json:"failures_url"` 39 | Label string `json:"label"` 40 | Total int `json:"total"` 41 | URL string `json:"url"` 42 | } `json:"rax"` 43 | } `json:"inventory_sources"` 44 | JobTemplates struct { 45 | Total int `json:"total"` 46 | URL string `json:"url"` 47 | } `json:"job_templates"` 48 | Jobs struct { 49 | Failed int `json:"failed"` 50 | FailureURL string `json:"failure_url"` 51 | Total int `json:"total"` 52 | URL string `json:"url"` 53 | } `json:"jobs"` 54 | Organizations struct { 55 | Total int `json:"total"` 56 | URL string `json:"url"` 57 | } `json:"organizations"` 58 | Projects struct { 59 | Failed int `json:"failed"` 60 | FailuresURL string `json:"failures_url"` 61 | Total int `json:"total"` 62 | URL string `json:"url"` 63 | } `json:"projects"` 64 | Related struct { 65 | JobsGraph string `json:"jobs_graph"` 66 | } `json:"related"` 67 | ScmTypes struct { 68 | Git struct { 69 | Failed int `json:"failed"` 70 | FailuresURL string `json:"failures_url"` 71 | Label string `json:"label"` 72 | Total int `json:"total"` 73 | URL string `json:"url"` 74 | } `json:"git"` 75 | Hg struct { 76 | Failed int `json:"failed"` 77 | FailuresURL string `json:"failures_url"` 78 | Label string `json:"label"` 79 | Total int `json:"total"` 80 | URL string `json:"url"` 81 | } `json:"hg"` 82 | Svn struct { 83 | Failed int `json:"failed"` 84 | FailuresURL string `json:"failures_url"` 85 | Label string `json:"label"` 86 | Total int `json:"total"` 87 | URL string `json:"url"` 88 | } `json:"svn"` 89 | } `json:"scm_types"` 90 | Teams struct { 91 | Total int `json:"total"` 92 | URL string `json:"url"` 93 | } `json:"teams"` 94 | Users struct { 95 | Total int `json:"total"` 96 | URL string `json:"url"` 97 | } `json:"users"` 98 | } 99 | -------------------------------------------------------------------------------- /model/inventory_scripts.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type InventoryScripts struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []CustomInventoryScript `json:"results"` 8 | } 9 | 10 | type CustomInventoryScript struct { 11 | Created string `json:"created"` 12 | Description string `json:"description"` 13 | ID int `json:"id"` 14 | Modified string `json:"modified"` 15 | Name string `json:"name"` 16 | Organization int `json:"organization"` 17 | Related struct { 18 | CreatedBy string `json:"created_by"` 19 | ModifiedBy string `json:"modified_by"` 20 | ObjectRoles string `json:"object_roles"` 21 | Organization string `json:"organization"` 22 | } `json:"related"` 23 | Script string `json:"script"` 24 | SummaryFields struct { 25 | CreatedBy struct { 26 | FirstName string `json:"first_name"` 27 | ID int `json:"id"` 28 | LastName string `json:"last_name"` 29 | Username string `json:"username"` 30 | } `json:"created_by"` 31 | ModifiedBy struct { 32 | FirstName string `json:"first_name"` 33 | ID int `json:"id"` 34 | LastName string `json:"last_name"` 35 | Username string `json:"username"` 36 | } `json:"modified_by"` 37 | ObjectRoles struct { 38 | AdminRole struct { 39 | Description string `json:"description"` 40 | ID int `json:"id"` 41 | Name string `json:"name"` 42 | } `json:"admin_role"` 43 | ReadRole struct { 44 | Description string `json:"description"` 45 | ID int `json:"id"` 46 | Name string `json:"name"` 47 | } `json:"read_role"` 48 | } `json:"object_roles"` 49 | Organization struct { 50 | Description string `json:"description"` 51 | ID int `json:"id"` 52 | Name string `json:"name"` 53 | } `json:"organization"` 54 | } `json:"summary_fields"` 55 | Type string `json:"type"` 56 | URL string `json:"url"` 57 | } 58 | -------------------------------------------------------------------------------- /model/inventory_sources.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type InventorySources struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []InventorySource `json:"results"` 8 | } 9 | 10 | type InventorySource struct { 11 | Created string `json:"created"` 12 | Credential string `json:"credential"` 13 | Description string `json:"description"` 14 | Group int `json:"group"` 15 | GroupBy string `json:"group_by"` 16 | HasSchedules bool `json:"has_schedules"` 17 | ID int `json:"id"` 18 | InstanceFilters string `json:"instance_filters"` 19 | Inventory int `json:"inventory"` 20 | LastJobFailed bool `json:"last_job_failed"` 21 | LastJobRun string `json:"last_job_run"` 22 | LastUpdateFailed bool `json:"last_update_failed"` 23 | LastUpdated string `json:"last_updated"` 24 | Modified string `json:"modified"` 25 | Name string `json:"name"` 26 | NextJobRun string `json:"next_job_run"` 27 | Overwrite bool `json:"overwrite"` 28 | OverwriteVars bool `json:"overwrite_vars"` 29 | Related struct { 30 | ActivityStream string `json:"activity_stream"` 31 | CreatedBy string `json:"created_by"` 32 | Group string `json:"group"` 33 | Groups string `json:"groups"` 34 | Hosts string `json:"hosts"` 35 | Inventory string `json:"inventory"` 36 | InventoryUpdates string `json:"inventory_updates"` 37 | ModifiedBy string `json:"modified_by"` 38 | NotificationTemplatesAny string `json:"notification_templates_any"` 39 | NotificationTemplatesError string `json:"notification_templates_error"` 40 | NotificationTemplatesSuccess string `json:"notification_templates_success"` 41 | Schedules string `json:"schedules"` 42 | Update string `json:"update"` 43 | } `json:"related"` 44 | Source string `json:"source"` 45 | SourcePath string `json:"source_path"` 46 | SourceRegions string `json:"source_regions"` 47 | SourceScript string `json:"source_script"` 48 | SourceVars string `json:"source_vars"` 49 | Status string `json:"status"` 50 | SummaryFields struct { 51 | CreatedBy struct { 52 | FirstName string `json:"first_name"` 53 | ID int `json:"id"` 54 | LastName string `json:"last_name"` 55 | Username string `json:"username"` 56 | } `json:"created_by"` 57 | Group struct { 58 | Description string `json:"description"` 59 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 60 | HasActiveFailures bool `json:"has_active_failures"` 61 | HasInventorySources bool `json:"has_inventory_sources"` 62 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 63 | ID int `json:"id"` 64 | Name string `json:"name"` 65 | TotalGroups int `json:"total_groups"` 66 | TotalHosts int `json:"total_hosts"` 67 | } `json:"group"` 68 | Inventory struct { 69 | Description string `json:"description"` 70 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 71 | HasActiveFailures bool `json:"has_active_failures"` 72 | HasInventorySources bool `json:"has_inventory_sources"` 73 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 74 | ID int `json:"id"` 75 | InventorySourcesWithFailures int `json:"inventory_sources_with_failures"` 76 | Name string `json:"name"` 77 | TotalGroups int `json:"total_groups"` 78 | TotalHosts int `json:"total_hosts"` 79 | TotalInventorySources int `json:"total_inventory_sources"` 80 | } `json:"inventory"` 81 | ModifiedBy struct { 82 | FirstName string `json:"first_name"` 83 | ID int `json:"id"` 84 | LastName string `json:"last_name"` 85 | Username string `json:"username"` 86 | } `json:"modified_by"` 87 | } `json:"summary_fields"` 88 | Type string `json:"type"` 89 | UpdateCacheTimeout int `json:"update_cache_timeout"` 90 | UpdateOnLaunch bool `json:"update_on_launch"` 91 | URL string `json:"url"` 92 | } 93 | -------------------------------------------------------------------------------- /model/job_events.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type JobEvents struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []JobEvent `json:"results"` 8 | } 9 | 10 | type JobEvent struct { 11 | Changed bool `json:"changed"` 12 | Counter int `json:"counter"` 13 | Created string `json:"created"` 14 | Event string `json:"event"` 15 | EventData struct{} `json:"event_data"` 16 | EventDisplay string `json:"event_display"` 17 | EventLevel int `json:"event_level"` 18 | Failed bool `json:"failed"` 19 | Host string `json:"host"` 20 | HostName string `json:"host_name"` 21 | ID int `json:"id"` 22 | Job int `json:"job"` 23 | Modified string `json:"modified"` 24 | Parent string `json:"parent"` 25 | Play string `json:"play"` 26 | Related struct { 27 | Children string `json:"children"` 28 | Job string `json:"job"` 29 | } `json:"related"` 30 | Role string `json:"role"` 31 | SummaryFields struct { 32 | Job struct { 33 | Description string `json:"description"` 34 | Failed bool `json:"failed"` 35 | ID int `json:"id"` 36 | JobTemplateID int `json:"job_template_id"` 37 | JobTemplateName string `json:"job_template_name"` 38 | Name string `json:"name"` 39 | Status string `json:"status"` 40 | } `json:"job"` 41 | Role struct{} `json:"role"` 42 | } `json:"summary_fields"` 43 | Task string `json:"task"` 44 | Type string `json:"type"` 45 | URL string `json:"url"` 46 | } 47 | -------------------------------------------------------------------------------- /model/job_templates.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type JobTemplates struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []JobTemplate `json:"results"` 8 | } 9 | 10 | type JobTemplate struct { 11 | AllowSimultaneous bool `json:"allow_simultaneous"` 12 | AskCredentialOnLaunch bool `json:"ask_credential_on_launch"` 13 | AskInventoryOnLaunch bool `json:"ask_inventory_on_launch"` 14 | AskJobTypeOnLaunch bool `json:"ask_job_type_on_launch"` 15 | AskLimitOnLaunch bool `json:"ask_limit_on_launch"` 16 | AskSkipTagsOnLaunch bool `json:"ask_skip_tags_on_launch"` 17 | AskTagsOnLaunch bool `json:"ask_tags_on_launch"` 18 | AskVariablesOnLaunch bool `json:"ask_variables_on_launch"` 19 | BecomeEnabled bool `json:"become_enabled"` 20 | CloudCredential int `json:"cloud_credential"` 21 | Created string `json:"created"` 22 | Credential int `json:"credential"` 23 | Description string `json:"description"` 24 | ExtraVars string `json:"extra_vars"` 25 | ForceHandlers bool `json:"force_handlers"` 26 | Forks int `json:"forks"` 27 | HasSchedules bool `json:"has_schedules"` 28 | HostConfigKey string `json:"host_config_key"` 29 | ID int `json:"id"` 30 | Inventory int `json:"inventory"` 31 | JobTags string `json:"job_tags"` 32 | JobType string `json:"job_type"` 33 | LastJobFailed bool `json:"last_job_failed"` 34 | LastJobRun string `json:"last_job_run"` 35 | Limit string `json:"limit"` 36 | Modified string `json:"modified"` 37 | Name string `json:"name"` 38 | NetworkCredential int `json:"network_credential"` 39 | NextJobRun string `json:"next_job_run"` 40 | Playbook string `json:"playbook"` 41 | Project int `json:"project"` 42 | Related struct { 43 | AccessList string `json:"access_list"` 44 | ActivityStream string `json:"activity_stream"` 45 | Callback string `json:"callback"` 46 | CloudCredential string `json:"cloud_credential"` 47 | CreatedBy string `json:"created_by"` 48 | Credential string `json:"credential"` 49 | Inventory string `json:"inventory"` 50 | Jobs string `json:"jobs"` 51 | Labels string `json:"labels"` 52 | LastJob string `json:"last_job"` 53 | Launch string `json:"launch"` 54 | ModifiedBy string `json:"modified_by"` 55 | NetworkCredential string `json:"network_credential"` 56 | NotificationTemplatesAny string `json:"notification_templates_any"` 57 | NotificationTemplatesError string `json:"notification_templates_error"` 58 | NotificationTemplatesSuccess string `json:"notification_templates_success"` 59 | ObjectRoles string `json:"object_roles"` 60 | Project string `json:"project"` 61 | Schedules string `json:"schedules"` 62 | SurveySpec string `json:"survey_spec"` 63 | } `json:"related"` 64 | SkipTags string `json:"skip_tags"` 65 | StartAtTask string `json:"start_at_task"` 66 | Status string `json:"status"` 67 | SummaryFields struct { 68 | CanCopy bool `json:"can_copy"` 69 | CanEdit bool `json:"can_edit"` 70 | CloudCredential struct { 71 | Cloud bool `json:"cloud"` 72 | Description string `json:"description"` 73 | ID int `json:"id"` 74 | Kind string `json:"kind"` 75 | Name string `json:"name"` 76 | } `json:"cloud_credential"` 77 | CreatedBy struct { 78 | FirstName string `json:"first_name"` 79 | ID int `json:"id"` 80 | LastName string `json:"last_name"` 81 | Username string `json:"username"` 82 | } `json:"created_by"` 83 | Credential struct { 84 | Cloud bool `json:"cloud"` 85 | Description string `json:"description"` 86 | ID int `json:"id"` 87 | Kind string `json:"kind"` 88 | Name string `json:"name"` 89 | } `json:"credential"` 90 | Inventory struct { 91 | Description string `json:"description"` 92 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 93 | HasActiveFailures bool `json:"has_active_failures"` 94 | HasInventorySources bool `json:"has_inventory_sources"` 95 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 96 | ID int `json:"id"` 97 | InventorySourcesWithFailures int `json:"inventory_sources_with_failures"` 98 | Name string `json:"name"` 99 | TotalGroups int `json:"total_groups"` 100 | TotalHosts int `json:"total_hosts"` 101 | TotalInventorySources int `json:"total_inventory_sources"` 102 | } `json:"inventory"` 103 | Labels struct { 104 | Count int `json:"count"` 105 | Results []struct { 106 | ID int `json:"id"` 107 | Name string `json:"name"` 108 | } `json:"results"` 109 | } `json:"labels"` 110 | LastJob struct { 111 | Description string `json:"description"` 112 | Failed bool `json:"failed"` 113 | Finished string `json:"finished"` 114 | ID int `json:"id"` 115 | Name string `json:"name"` 116 | Status string `json:"status"` 117 | } `json:"last_job"` 118 | LastUpdate struct { 119 | Description string `json:"description"` 120 | Failed bool `json:"failed"` 121 | ID int `json:"id"` 122 | Name string `json:"name"` 123 | Status string `json:"status"` 124 | } `json:"last_update"` 125 | ModifiedBy struct { 126 | FirstName string `json:"first_name"` 127 | ID int `json:"id"` 128 | LastName string `json:"last_name"` 129 | Username string `json:"username"` 130 | } `json:"modified_by"` 131 | NetworkCredential struct { 132 | Description string `json:"description"` 133 | ID int `json:"id"` 134 | Kind string `json:"kind"` 135 | Name string `json:"name"` 136 | } `json:"network_credential"` 137 | ObjectRoles struct { 138 | AdminRole struct { 139 | Description string `json:"description"` 140 | ID int `json:"id"` 141 | Name string `json:"name"` 142 | } `json:"admin_role"` 143 | ExecuteRole struct { 144 | Description string `json:"description"` 145 | ID int `json:"id"` 146 | Name string `json:"name"` 147 | } `json:"execute_role"` 148 | ReadRole struct { 149 | Description string `json:"description"` 150 | ID int `json:"id"` 151 | Name string `json:"name"` 152 | } `json:"read_role"` 153 | } `json:"object_roles"` 154 | Project struct { 155 | Description string `json:"description"` 156 | ID int `json:"id"` 157 | Name string `json:"name"` 158 | Status string `json:"status"` 159 | } `json:"project"` 160 | RecentJobs []struct { 161 | Finished string `json:"finished"` 162 | ID int `json:"id"` 163 | Status string `json:"status"` 164 | } `json:"recent_jobs"` 165 | } `json:"summary_fields"` 166 | SurveyEnabled bool `json:"survey_enabled"` 167 | Type string `json:"type"` 168 | URL string `json:"url"` 169 | Verbosity int `json:"verbosity"` 170 | } 171 | -------------------------------------------------------------------------------- /model/jobs.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Jobs struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []Job `json:"results"` 8 | } 9 | 10 | type Job struct { 11 | AskCredentialOnLaunch bool `json:"ask_credential_on_launch"` 12 | AskInventoryOnLaunch bool `json:"ask_inventory_on_launch"` 13 | AskJobTypeOnLaunch bool `json:"ask_job_type_on_launch"` 14 | AskLimitOnLaunch bool `json:"ask_limit_on_launch"` 15 | AskSkipTagsOnLaunch bool `json:"ask_skip_tags_on_launch"` 16 | AskTagsOnLaunch bool `json:"ask_tags_on_launch"` 17 | AskVariablesOnLaunch bool `json:"ask_variables_on_launch"` 18 | CloudCredential string `json:"cloud_credential"` 19 | Created string `json:"created"` 20 | Credential int `json:"credential"` 21 | Description string `json:"description"` 22 | Elapsed float64 `json:"elapsed"` 23 | ExtraVars string `json:"extra_vars"` 24 | Failed bool `json:"failed"` 25 | Finished string `json:"finished"` 26 | ForceHandlers bool `json:"force_handlers"` 27 | Forks int `json:"forks"` 28 | ID int `json:"id"` 29 | Inventory int `json:"inventory"` 30 | JobArgs string `json:"job_args"` 31 | JobCwd string `json:"job_cwd"` 32 | JobEnv struct { 33 | ANSIBLECALLBACKPLUGINS string `json:"ANSIBLE_CALLBACK_PLUGINS"` 34 | ANSIBLEFORCECOLOR string `json:"ANSIBLE_FORCE_COLOR"` 35 | ANSIBLEHOSTKEYCHECKING string `json:"ANSIBLE_HOST_KEY_CHECKING"` 36 | ANSIBLEPARAMIKORECORDHOSTKEYS string `json:"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS"` 37 | ANSIBLESSHCONTROLPATH string `json:"ANSIBLE_SSH_CONTROL_PATH"` 38 | ANSIBLEUSEVENV string `json:"ANSIBLE_USE_VENV"` 39 | ANSIBLEVENVPATH string `json:"ANSIBLE_VENV_PATH"` 40 | CALLBACKCONSUMERPORT string `json:"CALLBACK_CONSUMER_PORT"` 41 | CELERYLOADER string `json:"CELERY_LOADER"` 42 | CELERYLOGFILE string `json:"CELERY_LOG_FILE"` 43 | CELERYLOGLEVEL string `json:"CELERY_LOG_LEVEL"` 44 | CELERYLOGREDIRECT string `json:"CELERY_LOG_REDIRECT"` 45 | CELERYLOGREDIRECTLEVEL string `json:"CELERY_LOG_REDIRECT_LEVEL"` 46 | DJANGOLIVETESTSERVERADDRESS string `json:"DJANGO_LIVE_TEST_SERVER_ADDRESS"` 47 | DJANGOPROJECTDIR string `json:"DJANGO_PROJECT_DIR"` 48 | DJANGOSETTINGSMODULE string `json:"DJANGO_SETTINGS_MODULE"` 49 | HOME string `json:"HOME"` 50 | INVENTORYHOSTVARS string `json:"INVENTORY_HOSTVARS"` 51 | INVENTORYID string `json:"INVENTORY_ID"` 52 | JOBID string `json:"JOB_ID"` 53 | LANG string `json:"LANG"` 54 | PATH string `json:"PATH"` 55 | PROOTTMPDIR string `json:"PROOT_TMP_DIR"` 56 | PS1 string `json:"PS1"` 57 | PWD string `json:"PWD"` 58 | PYTHONPATH string `json:"PYTHONPATH"` 59 | RESTAPITOKEN string `json:"REST_API_TOKEN"` 60 | RESTAPIURL string `json:"REST_API_URL"` 61 | SHLVL string `json:"SHLVL"` 62 | SUPERVISORENABLED string `json:"SUPERVISOR_ENABLED"` 63 | SUPERVISORGROUPNAME string `json:"SUPERVISOR_GROUP_NAME"` 64 | SUPERVISORPROCESSNAME string `json:"SUPERVISOR_PROCESS_NAME"` 65 | SUPERVISORSERVERURL string `json:"SUPERVISOR_SERVER_URL"` 66 | TZ string `json:"TZ"` 67 | USER string `json:"USER"` 68 | VIRTUALENV string `json:"VIRTUAL_ENV"` 69 | MPFORKLOGFILE string `json:"_MP_FORK_LOGFILE_"` 70 | MPFORKLOGFORMAT string `json:"_MP_FORK_LOGFORMAT_"` 71 | MPFORKLOGLEVEL string `json:"_MP_FORK_LOGLEVEL_"` 72 | } `json:"job_env"` 73 | JobExplanation string `json:"job_explanation"` 74 | JobTags string `json:"job_tags"` 75 | JobTemplate int `json:"job_template"` 76 | JobType string `json:"job_type"` 77 | LaunchType string `json:"launch_type"` 78 | Limit string `json:"limit"` 79 | Modified string `json:"modified"` 80 | Name string `json:"name"` 81 | NetworkCredential string `json:"network_credential"` 82 | PasswordsNeededToStart []interface{} `json:"passwords_needed_to_start"` 83 | Playbook string `json:"playbook"` 84 | Project int `json:"project"` 85 | Related struct { 86 | ActivityStream string `json:"activity_stream"` 87 | Cancel string `json:"cancel"` 88 | CreatedBy string `json:"created_by"` 89 | Credential string `json:"credential"` 90 | Inventory string `json:"inventory"` 91 | JobEvents string `json:"job_events"` 92 | JobHostSummaries string `json:"job_host_summaries"` 93 | JobPlays string `json:"job_plays"` 94 | JobTasks string `json:"job_tasks"` 95 | JobTemplate string `json:"job_template"` 96 | Labels string `json:"labels"` 97 | Notifications string `json:"notifications"` 98 | Project string `json:"project"` 99 | Relaunch string `json:"relaunch"` 100 | Start string `json:"start"` 101 | Stdout string `json:"stdout"` 102 | UnifiedJobTemplate string `json:"unified_job_template"` 103 | } `json:"related"` 104 | ResultStdout string `json:"result_stdout"` 105 | ResultTraceback string `json:"result_traceback"` 106 | SkipTags string `json:"skip_tags"` 107 | StartAtTask string `json:"start_at_task"` 108 | Started string `json:"started"` 109 | Status string `json:"status"` 110 | SummaryFields struct { 111 | CreatedBy struct { 112 | FirstName string `json:"first_name"` 113 | ID int `json:"id"` 114 | LastName string `json:"last_name"` 115 | Username string `json:"username"` 116 | } `json:"created_by"` 117 | Credential struct { 118 | Cloud bool `json:"cloud"` 119 | Description string `json:"description"` 120 | ID int `json:"id"` 121 | Kind string `json:"kind"` 122 | Name string `json:"name"` 123 | } `json:"credential"` 124 | Inventory struct { 125 | Description string `json:"description"` 126 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 127 | HasActiveFailures bool `json:"has_active_failures"` 128 | HasInventorySources bool `json:"has_inventory_sources"` 129 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 130 | ID int `json:"id"` 131 | InventorySourcesWithFailures int `json:"inventory_sources_with_failures"` 132 | Name string `json:"name"` 133 | TotalGroups int `json:"total_groups"` 134 | TotalHosts int `json:"total_hosts"` 135 | TotalInventorySources int `json:"total_inventory_sources"` 136 | } `json:"inventory"` 137 | JobTemplate struct { 138 | Description string `json:"description"` 139 | ID int `json:"id"` 140 | Name string `json:"name"` 141 | } `json:"job_template"` 142 | Labels struct { 143 | Count int `json:"count"` 144 | Results []interface{} `json:"results"` 145 | } `json:"labels"` 146 | Project struct { 147 | Description string `json:"description"` 148 | ID int `json:"id"` 149 | Name string `json:"name"` 150 | Status string `json:"status"` 151 | } `json:"project"` 152 | UnifiedJobTemplate struct { 153 | Description string `json:"description"` 154 | ID int `json:"id"` 155 | Name string `json:"name"` 156 | UnifiedJobType string `json:"unified_job_type"` 157 | } `json:"unified_job_template"` 158 | } `json:"summary_fields"` 159 | Type string `json:"type"` 160 | UnifiedJobTemplate int `json:"unified_job_template"` 161 | URL string `json:"url"` 162 | Verbosity int `json:"verbosity"` 163 | } 164 | -------------------------------------------------------------------------------- /model/labels.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Labels struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []Label `json:"results"` 8 | } 9 | 10 | type Label struct { 11 | Created string `json:"created"` 12 | ID int `json:"id"` 13 | Modified string `json:"modified"` 14 | Name string `json:"name"` 15 | Organization int `json:"organization"` 16 | Related struct { 17 | CreatedBy string `json:"created_by"` 18 | ModifiedBy string `json:"modified_by"` 19 | Organization string `json:"organization"` 20 | } `json:"related"` 21 | SummaryFields struct { 22 | CreatedBy struct { 23 | FirstName string `json:"first_name"` 24 | ID int `json:"id"` 25 | LastName string `json:"last_name"` 26 | Username string `json:"username"` 27 | } `json:"created_by"` 28 | ModifiedBy struct { 29 | FirstName string `json:"first_name"` 30 | ID int `json:"id"` 31 | LastName string `json:"last_name"` 32 | Username string `json:"username"` 33 | } `json:"modified_by"` 34 | Organization struct { 35 | Description string `json:"description"` 36 | ID int `json:"id"` 37 | Name string `json:"name"` 38 | } `json:"organization"` 39 | } `json:"summary_fields"` 40 | Type string `json:"type"` 41 | URL string `json:"url"` 42 | } 43 | -------------------------------------------------------------------------------- /model/me.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Me struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []User `json:"results"` 8 | } 9 | -------------------------------------------------------------------------------- /model/notification_templates.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type NotificationTemplates struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []NotificationTemplate `json:"results"` 8 | } 9 | 10 | type NotificationTemplate struct { 11 | Created string `json:"created"` 12 | Description string `json:"description"` 13 | ID int `json:"id"` 14 | Modified string `json:"modified"` 15 | Name string `json:"name"` 16 | NotificationConfiguration struct { 17 | Headers struct { 18 | X_Ansible string `json:"X-Ansible"` 19 | X_Auth_Token string `json:"X-Auth-Token"` 20 | } `json:"headers"` 21 | URL string `json:"url"` 22 | } `json:"notification_configuration"` 23 | NotificationType string `json:"notification_type"` 24 | Organization int `json:"organization"` 25 | Related struct { 26 | CreatedBy string `json:"created_by"` 27 | ModifiedBy string `json:"modified_by"` 28 | Notifications string `json:"notifications"` 29 | Organization string `json:"organization"` 30 | Test string `json:"test"` 31 | } `json:"related"` 32 | SummaryFields struct { 33 | CreatedBy struct { 34 | FirstName string `json:"first_name"` 35 | ID int `json:"id"` 36 | LastName string `json:"last_name"` 37 | Username string `json:"username"` 38 | } `json:"created_by"` 39 | ModifiedBy struct { 40 | FirstName string `json:"first_name"` 41 | ID int `json:"id"` 42 | LastName string `json:"last_name"` 43 | Username string `json:"username"` 44 | } `json:"modified_by"` 45 | Organization struct { 46 | Description string `json:"description"` 47 | ID int `json:"id"` 48 | Name string `json:"name"` 49 | } `json:"organization"` 50 | RecentNotifications []struct { 51 | Created string `json:"created"` 52 | ID int `json:"id"` 53 | Status string `json:"status"` 54 | } `json:"recent_notifications"` 55 | } `json:"summary_fields"` 56 | Type string `json:"type"` 57 | URL string `json:"url"` 58 | } 59 | -------------------------------------------------------------------------------- /model/notifications.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Notifications struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []Notification `json:"results"` 8 | } 9 | 10 | type Notification struct { 11 | Created string `json:"created"` 12 | Error string `json:"error"` 13 | ID int `json:"id"` 14 | Modified string `json:"modified"` 15 | NotificationTemplate int `json:"notification_template"` 16 | NotificationType string `json:"notification_type"` 17 | NotificationsSent int `json:"notifications_sent"` 18 | Recipients string `json:"recipients"` 19 | Related struct { 20 | NotificationTemplate string `json:"notification_template"` 21 | } `json:"related"` 22 | Status string `json:"status"` 23 | Subject string `json:"subject"` 24 | SummaryFields struct { 25 | NotificationTemplate struct { 26 | Description string `json:"description"` 27 | ID int `json:"id"` 28 | Name string `json:"name"` 29 | } `json:"notification_template"` 30 | } `json:"summary_fields"` 31 | Type string `json:"type"` 32 | URL string `json:"url"` 33 | } 34 | -------------------------------------------------------------------------------- /model/ping.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Ping struct { 4 | Ha bool `json:"ha"` 5 | Instances struct { 6 | Primary string `json:"primary"` 7 | Secondaries []interface{} `json:"secondaries"` 8 | } `json:"instances"` 9 | Role string `json:"role"` 10 | Version string `json:"version"` 11 | } 12 | -------------------------------------------------------------------------------- /model/projects.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Projects struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []Project `json:"results"` 8 | } 9 | 10 | type Project struct { 11 | Created string `json:"created"` 12 | Credential int `json:"credential"` 13 | Description string `json:"description"` 14 | HasSchedules bool `json:"has_schedules"` 15 | ID int `json:"id"` 16 | LastJobFailed bool `json:"last_job_failed"` 17 | LastJobRun string `json:"last_job_run"` 18 | LastUpdateFailed bool `json:"last_update_failed"` 19 | LastUpdated string `json:"last_updated"` 20 | LocalPath string `json:"local_path"` 21 | Modified string `json:"modified"` 22 | Name string `json:"name"` 23 | NextJobRun string `json:"next_job_run"` 24 | Organization int `json:"organization"` 25 | Related struct { 26 | AccessList string `json:"access_list"` 27 | ActivityStream string `json:"activity_stream"` 28 | CreatedBy string `json:"created_by"` 29 | Credential string `json:"credential"` 30 | LastJob string `json:"last_job"` 31 | LastUpdate string `json:"last_update"` 32 | NextSchedule string `json:"next_schedule"` 33 | NotificationTemplatesAny string `json:"notification_templates_any"` 34 | NotificationTemplatesError string `json:"notification_templates_error"` 35 | NotificationTemplatesSuccess string `json:"notification_templates_success"` 36 | ObjectRoles string `json:"object_roles"` 37 | Organization string `json:"organization"` 38 | Playbooks string `json:"playbooks"` 39 | ProjectUpdates string `json:"project_updates"` 40 | Schedules string `json:"schedules"` 41 | Teams string `json:"teams"` 42 | Update string `json:"update"` 43 | } `json:"related"` 44 | ScmBranch string `json:"scm_branch"` 45 | ScmClean bool `json:"scm_clean"` 46 | ScmDeleteOnNextUpdate bool `json:"scm_delete_on_next_update"` 47 | ScmDeleteOnUpdate bool `json:"scm_delete_on_update"` 48 | ScmType string `json:"scm_type"` 49 | ScmUpdateCacheTimeout int `json:"scm_update_cache_timeout"` 50 | ScmUpdateOnLaunch bool `json:"scm_update_on_launch"` 51 | ScmURL string `json:"scm_url"` 52 | Status string `json:"status"` 53 | SummaryFields struct { 54 | CreatedBy struct { 55 | FirstName string `json:"first_name"` 56 | ID int `json:"id"` 57 | LastName string `json:"last_name"` 58 | Username string `json:"username"` 59 | } `json:"created_by"` 60 | Credential struct { 61 | Cloud bool `json:"cloud"` 62 | Description string `json:"description"` 63 | ID int `json:"id"` 64 | Kind string `json:"kind"` 65 | Name string `json:"name"` 66 | } `json:"credential"` 67 | LastJob struct { 68 | Description string `json:"description"` 69 | Failed bool `json:"failed"` 70 | Finished string `json:"finished"` 71 | ID int `json:"id"` 72 | Name string `json:"name"` 73 | Status string `json:"status"` 74 | } `json:"last_job"` 75 | LastUpdate struct { 76 | Description string `json:"description"` 77 | Failed bool `json:"failed"` 78 | ID int `json:"id"` 79 | Name string `json:"name"` 80 | Status string `json:"status"` 81 | } `json:"last_update"` 82 | ObjectRoles struct { 83 | AdminRole struct { 84 | Description string `json:"description"` 85 | ID int `json:"id"` 86 | Name string `json:"name"` 87 | } `json:"admin_role"` 88 | ReadRole struct { 89 | Description string `json:"description"` 90 | ID int `json:"id"` 91 | Name string `json:"name"` 92 | } `json:"read_role"` 93 | UpdateRole struct { 94 | Description string `json:"description"` 95 | ID int `json:"id"` 96 | Name string `json:"name"` 97 | } `json:"update_role"` 98 | UseRole struct { 99 | Description string `json:"description"` 100 | ID int `json:"id"` 101 | Name string `json:"name"` 102 | } `json:"use_role"` 103 | } `json:"object_roles"` 104 | Organization struct { 105 | Description string `json:"description"` 106 | ID int `json:"id"` 107 | Name string `json:"name"` 108 | } `json:"organization"` 109 | } `json:"summary_fields"` 110 | Type string `json:"type"` 111 | URL string `json:"url"` 112 | } 113 | -------------------------------------------------------------------------------- /model/roles.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Roles struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []Role `json:"results"` 8 | } 9 | 10 | type Role struct { 11 | Description string `json:"description"` 12 | ID int `json:"id"` 13 | Name string `json:"name"` 14 | Related struct { 15 | Teams string `json:"teams"` 16 | Users string `json:"users"` 17 | } `json:"related"` 18 | SummaryFields struct{} `json:"summary_fields"` 19 | Type string `json:"type"` 20 | URL string `json:"url"` 21 | } 22 | -------------------------------------------------------------------------------- /model/schedules.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Schedules struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []Schedule `json:"results"` 8 | } 9 | 10 | type Schedule struct { 11 | Created string `json:"created"` 12 | Description string `json:"description"` 13 | Dtend string `json:"dtend"` 14 | Dtstart string `json:"dtstart"` 15 | Enabled bool `json:"enabled"` 16 | ExtraData struct { 17 | Days string `json:"days"` 18 | } `json:"extra_data"` 19 | ID int `json:"id"` 20 | Modified string `json:"modified"` 21 | Name string `json:"name"` 22 | NextRun string `json:"next_run"` 23 | Related struct { 24 | UnifiedJobTemplate string `json:"unified_job_template"` 25 | UnifiedJobs string `json:"unified_jobs"` 26 | } `json:"related"` 27 | Rrule string `json:"rrule"` 28 | SummaryFields struct { 29 | UnifiedJobTemplate struct { 30 | Description string `json:"description"` 31 | ID int `json:"id"` 32 | Name string `json:"name"` 33 | UnifiedJobType string `json:"unified_job_type"` 34 | } `json:"unified_job_template"` 35 | } `json:"summary_fields"` 36 | Type string `json:"type"` 37 | UnifiedJobTemplate int `json:"unified_job_template"` 38 | URL string `json:"url"` 39 | } 40 | -------------------------------------------------------------------------------- /model/system_job_templates.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type SystemJobTemplates struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []SystemJobTemplate `json:"results"` 8 | } 9 | 10 | type SystemJobTemplate struct { 11 | Created string `json:"created"` 12 | Description string `json:"description"` 13 | HasSchedules bool `json:"has_schedules"` 14 | ID int `json:"id"` 15 | JobType string `json:"job_type"` 16 | LastJobFailed bool `json:"last_job_failed"` 17 | LastJobRun string `json:"last_job_run"` 18 | Modified string `json:"modified"` 19 | Name string `json:"name"` 20 | NextJobRun string `json:"next_job_run"` 21 | Related struct { 22 | Jobs string `json:"jobs"` 23 | LastJob string `json:"last_job"` 24 | Launch string `json:"launch"` 25 | NextSchedule string `json:"next_schedule"` 26 | NotificationTemplatesAny string `json:"notification_templates_any"` 27 | NotificationTemplatesError string `json:"notification_templates_error"` 28 | NotificationTemplatesSuccess string `json:"notification_templates_success"` 29 | Schedules string `json:"schedules"` 30 | } `json:"related"` 31 | Status string `json:"status"` 32 | SummaryFields struct { 33 | LastJob struct { 34 | Description string `json:"description"` 35 | Failed bool `json:"failed"` 36 | Finished string `json:"finished"` 37 | ID int `json:"id"` 38 | Name string `json:"name"` 39 | Status string `json:"status"` 40 | } `json:"last_job"` 41 | LastUpdate struct { 42 | Description string `json:"description"` 43 | Failed bool `json:"failed"` 44 | ID int `json:"id"` 45 | Name string `json:"name"` 46 | Status string `json:"status"` 47 | } `json:"last_update"` 48 | } `json:"summary_fields"` 49 | Type string `json:"type"` 50 | URL string `json:"url"` 51 | } 52 | -------------------------------------------------------------------------------- /model/system_jobs.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type SystemJobs struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []SystemJob `json:"results"` 8 | } 9 | 10 | type SystemJob struct { 11 | Created string `json:"created"` 12 | Description string `json:"description"` 13 | Elapsed float64 `json:"elapsed"` 14 | ExtraVars string `json:"extra_vars"` 15 | Failed bool `json:"failed"` 16 | Finished string `json:"finished"` 17 | ID int `json:"id"` 18 | JobArgs string `json:"job_args"` 19 | JobCwd string `json:"job_cwd"` 20 | JobEnv struct { 21 | ANSIBLEFORCECOLOR string `json:"ANSIBLE_FORCE_COLOR"` 22 | ANSIBLEHOSTKEYCHECKING string `json:"ANSIBLE_HOST_KEY_CHECKING"` 23 | ANSIBLEPARAMIKORECORDHOSTKEYS string `json:"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS"` 24 | ANSIBLEUSEVENV string `json:"ANSIBLE_USE_VENV"` 25 | ANSIBLEVENVPATH string `json:"ANSIBLE_VENV_PATH"` 26 | CELERYLOADER string `json:"CELERY_LOADER"` 27 | CELERYLOGFILE string `json:"CELERY_LOG_FILE"` 28 | CELERYLOGLEVEL string `json:"CELERY_LOG_LEVEL"` 29 | CELERYLOGREDIRECT string `json:"CELERY_LOG_REDIRECT"` 30 | CELERYLOGREDIRECTLEVEL string `json:"CELERY_LOG_REDIRECT_LEVEL"` 31 | DJANGOLIVETESTSERVERADDRESS string `json:"DJANGO_LIVE_TEST_SERVER_ADDRESS"` 32 | DJANGOPROJECTDIR string `json:"DJANGO_PROJECT_DIR"` 33 | DJANGOSETTINGSMODULE string `json:"DJANGO_SETTINGS_MODULE"` 34 | HOME string `json:"HOME"` 35 | LANG string `json:"LANG"` 36 | PATH string `json:"PATH"` 37 | PS1 string `json:"PS1"` 38 | PWD string `json:"PWD"` 39 | SHLVL string `json:"SHLVL"` 40 | SUPERVISORENABLED string `json:"SUPERVISOR_ENABLED"` 41 | SUPERVISORGROUPNAME string `json:"SUPERVISOR_GROUP_NAME"` 42 | SUPERVISORPROCESSNAME string `json:"SUPERVISOR_PROCESS_NAME"` 43 | SUPERVISORSERVERURL string `json:"SUPERVISOR_SERVER_URL"` 44 | TZ string `json:"TZ"` 45 | USER string `json:"USER"` 46 | VIRTUALENV string `json:"VIRTUAL_ENV"` 47 | MPFORKLOGFILE string `json:"_MP_FORK_LOGFILE_"` 48 | MPFORKLOGFORMAT string `json:"_MP_FORK_LOGFORMAT_"` 49 | MPFORKLOGLEVEL string `json:"_MP_FORK_LOGLEVEL_"` 50 | } `json:"job_env"` 51 | JobExplanation string `json:"job_explanation"` 52 | JobType string `json:"job_type"` 53 | LaunchType string `json:"launch_type"` 54 | Modified string `json:"modified"` 55 | Name string `json:"name"` 56 | Related struct { 57 | Cancel string `json:"cancel"` 58 | Notifications string `json:"notifications"` 59 | SystemJobTemplate string `json:"system_job_template"` 60 | UnifiedJobTemplate string `json:"unified_job_template"` 61 | } `json:"related"` 62 | ResultStdout string `json:"result_stdout"` 63 | ResultTraceback string `json:"result_traceback"` 64 | Started string `json:"started"` 65 | Status string `json:"status"` 66 | SummaryFields struct { 67 | UnifiedJobTemplate struct { 68 | Description string `json:"description"` 69 | ID int `json:"id"` 70 | Name string `json:"name"` 71 | UnifiedJobType string `json:"unified_job_type"` 72 | } `json:"unified_job_template"` 73 | } `json:"summary_fields"` 74 | SystemJobTemplate int `json:"system_job_template"` 75 | Type string `json:"type"` 76 | UnifiedJobTemplate int `json:"unified_job_template"` 77 | URL string `json:"url"` 78 | } 79 | -------------------------------------------------------------------------------- /model/teams.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Teams struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []Team `json:"results"` 8 | } 9 | 10 | type Team struct { 11 | Created string `json:"created"` 12 | Description string `json:"description"` 13 | ID int `json:"id"` 14 | Modified string `json:"modified"` 15 | Name string `json:"name"` 16 | Organization int `json:"organization"` 17 | Related struct { 18 | AccessList string `json:"access_list"` 19 | ActivityStream string `json:"activity_stream"` 20 | CreatedBy string `json:"created_by"` 21 | Credentials string `json:"credentials"` 22 | ModifiedBy string `json:"modified_by"` 23 | ObjectRoles string `json:"object_roles"` 24 | Organization string `json:"organization"` 25 | Projects string `json:"projects"` 26 | Roles string `json:"roles"` 27 | Users string `json:"users"` 28 | } `json:"related"` 29 | SummaryFields struct { 30 | CreatedBy struct { 31 | FirstName string `json:"first_name"` 32 | ID int `json:"id"` 33 | LastName string `json:"last_name"` 34 | Username string `json:"username"` 35 | } `json:"created_by"` 36 | ModifiedBy struct { 37 | FirstName string `json:"first_name"` 38 | ID int `json:"id"` 39 | LastName string `json:"last_name"` 40 | Username string `json:"username"` 41 | } `json:"modified_by"` 42 | ObjectRoles struct { 43 | AdminRole struct { 44 | Description string `json:"description"` 45 | ID int `json:"id"` 46 | Name string `json:"name"` 47 | } `json:"admin_role"` 48 | MemberRole struct { 49 | Description string `json:"description"` 50 | ID int `json:"id"` 51 | Name string `json:"name"` 52 | } `json:"member_role"` 53 | ReadRole struct { 54 | Description string `json:"description"` 55 | ID int `json:"id"` 56 | Name string `json:"name"` 57 | } `json:"read_role"` 58 | } `json:"object_roles"` 59 | Organization struct { 60 | Description string `json:"description"` 61 | ID int `json:"id"` 62 | Name string `json:"name"` 63 | } `json:"organization"` 64 | } `json:"summary_fields"` 65 | Type string `json:"type"` 66 | URL string `json:"url"` 67 | } 68 | -------------------------------------------------------------------------------- /model/unified_job_templates.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type UnifiedJobTemplates struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []UnifiedJobTemplate `json:"results"` 8 | } 9 | 10 | type UnifiedJobTemplate struct { 11 | Created string `json:"created"` 12 | Description string `json:"description"` 13 | HasSchedules bool `json:"has_schedules"` 14 | ID int `json:"id"` 15 | JobType string `json:"job_type"` 16 | LastJobFailed bool `json:"last_job_failed"` 17 | LastJobRun string `json:"last_job_run"` 18 | Modified string `json:"modified"` 19 | Name string `json:"name"` 20 | NextJobRun string `json:"next_job_run"` 21 | Related struct { 22 | Jobs string `json:"jobs"` 23 | LastJob string `json:"last_job"` 24 | Launch string `json:"launch"` 25 | NextSchedule string `json:"next_schedule"` 26 | NotificationTemplatesAny string `json:"notification_templates_any"` 27 | NotificationTemplatesError string `json:"notification_templates_error"` 28 | NotificationTemplatesSuccess string `json:"notification_templates_success"` 29 | Schedules string `json:"schedules"` 30 | } `json:"related"` 31 | Status string `json:"status"` 32 | SummaryFields struct { 33 | LastJob struct { 34 | Description string `json:"description"` 35 | Failed bool `json:"failed"` 36 | Finished string `json:"finished"` 37 | ID int `json:"id"` 38 | Name string `json:"name"` 39 | Status string `json:"status"` 40 | } `json:"last_job"` 41 | LastUpdate struct { 42 | Description string `json:"description"` 43 | Failed bool `json:"failed"` 44 | ID int `json:"id"` 45 | Name string `json:"name"` 46 | Status string `json:"status"` 47 | } `json:"last_update"` 48 | } `json:"summary_fields"` 49 | Type string `json:"type"` 50 | URL string `json:"url"` 51 | } 52 | -------------------------------------------------------------------------------- /model/unified_jobs.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type UnifiedJobs struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []UnifiedJob `json:"results"` 8 | } 9 | 10 | type UnifiedJob struct { 11 | Created string `json:"created"` 12 | Description string `json:"description"` 13 | Elapsed float64 `json:"elapsed"` 14 | ExtraVars string `json:"extra_vars"` 15 | Failed bool `json:"failed"` 16 | Finished string `json:"finished"` 17 | ID int `json:"id"` 18 | JobArgs string `json:"job_args"` 19 | JobCwd string `json:"job_cwd"` 20 | JobEnv struct { 21 | ANSIBLEFORCECOLOR string `json:"ANSIBLE_FORCE_COLOR"` 22 | ANSIBLEHOSTKEYCHECKING string `json:"ANSIBLE_HOST_KEY_CHECKING"` 23 | ANSIBLEPARAMIKORECORDHOSTKEYS string `json:"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS"` 24 | ANSIBLEUSEVENV string `json:"ANSIBLE_USE_VENV"` 25 | ANSIBLEVENVPATH string `json:"ANSIBLE_VENV_PATH"` 26 | CELERYLOADER string `json:"CELERY_LOADER"` 27 | CELERYLOGFILE string `json:"CELERY_LOG_FILE"` 28 | CELERYLOGLEVEL string `json:"CELERY_LOG_LEVEL"` 29 | CELERYLOGREDIRECT string `json:"CELERY_LOG_REDIRECT"` 30 | CELERYLOGREDIRECTLEVEL string `json:"CELERY_LOG_REDIRECT_LEVEL"` 31 | DJANGOLIVETESTSERVERADDRESS string `json:"DJANGO_LIVE_TEST_SERVER_ADDRESS"` 32 | DJANGOPROJECTDIR string `json:"DJANGO_PROJECT_DIR"` 33 | DJANGOSETTINGSMODULE string `json:"DJANGO_SETTINGS_MODULE"` 34 | HOME string `json:"HOME"` 35 | LANG string `json:"LANG"` 36 | PATH string `json:"PATH"` 37 | PS1 string `json:"PS1"` 38 | PWD string `json:"PWD"` 39 | SHLVL string `json:"SHLVL"` 40 | SUPERVISORENABLED string `json:"SUPERVISOR_ENABLED"` 41 | SUPERVISORGROUPNAME string `json:"SUPERVISOR_GROUP_NAME"` 42 | SUPERVISORPROCESSNAME string `json:"SUPERVISOR_PROCESS_NAME"` 43 | SUPERVISORSERVERURL string `json:"SUPERVISOR_SERVER_URL"` 44 | TZ string `json:"TZ"` 45 | USER string `json:"USER"` 46 | VIRTUALENV string `json:"VIRTUAL_ENV"` 47 | MPFORKLOGFILE string `json:"_MP_FORK_LOGFILE_"` 48 | MPFORKLOGFORMAT string `json:"_MP_FORK_LOGFORMAT_"` 49 | MPFORKLOGLEVEL string `json:"_MP_FORK_LOGLEVEL_"` 50 | } `json:"job_env"` 51 | JobExplanation string `json:"job_explanation"` 52 | JobType string `json:"job_type"` 53 | LaunchType string `json:"launch_type"` 54 | Modified string `json:"modified"` 55 | Name string `json:"name"` 56 | Related struct { 57 | Cancel string `json:"cancel"` 58 | Notifications string `json:"notifications"` 59 | SystemJobTemplate string `json:"system_job_template"` 60 | UnifiedJobTemplate string `json:"unified_job_template"` 61 | } `json:"related"` 62 | ResultStdout string `json:"result_stdout"` 63 | ResultTraceback string `json:"result_traceback"` 64 | Started string `json:"started"` 65 | Status string `json:"status"` 66 | SummaryFields struct { 67 | UnifiedJobTemplate struct { 68 | Description string `json:"description"` 69 | ID int `json:"id"` 70 | Name string `json:"name"` 71 | UnifiedJobType string `json:"unified_job_type"` 72 | } `json:"unified_job_template"` 73 | } `json:"summary_fields"` 74 | SystemJobTemplate int `json:"system_job_template"` 75 | Type string `json:"type"` 76 | UnifiedJobTemplate int `json:"unified_job_template"` 77 | URL string `json:"url"` 78 | } 79 | -------------------------------------------------------------------------------- /model/users.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | type Users struct { 4 | Count int `json:"count"` 5 | Next string `json:"next"` 6 | Previous string `json:"previous"` 7 | Results []User `json:"results"` 8 | } 9 | 10 | type User struct { 11 | Auth []interface{} `json:"auth"` 12 | Created string `json:"created"` 13 | Email string `json:"email"` 14 | ExternalAccount string `json:"external_account"` 15 | FirstName string `json:"first_name"` 16 | ID int `json:"id"` 17 | IsSuperuser bool `json:"is_superuser"` 18 | IsSystemAuditor bool `json:"is_system_auditor"` 19 | LastName string `json:"last_name"` 20 | LdapDn string `json:"ldap_dn"` 21 | Related struct { 22 | AccessList string `json:"access_list"` 23 | ActivityStream string `json:"activity_stream"` 24 | AdminOfOrganizations string `json:"admin_of_organizations"` 25 | Credentials string `json:"credentials"` 26 | Organizations string `json:"organizations"` 27 | Projects string `json:"projects"` 28 | Roles string `json:"roles"` 29 | Teams string `json:"teams"` 30 | } `json:"related"` 31 | Type string `json:"type"` 32 | URL string `json:"url"` 33 | Username string `json:"username"` 34 | } 35 | -------------------------------------------------------------------------------- /towerapi/authtoken/authtoken.go: -------------------------------------------------------------------------------- 1 | package authtoken 2 | 3 | import ( 4 | "github.com/mpeter/go-towerapi/towerapi/errors" 5 | "github.com/mpeter/sling" 6 | ) 7 | 8 | const basePath = "authtoken/" 9 | 10 | // Service is an interface for interfacing with the 11 | // endpoints of the Ansible Tower API 12 | type Service struct { 13 | sling *sling.Sling 14 | } 15 | 16 | // NewService handles communication with auth token related methods of the 17 | // Ansible Tower API. 18 | func NewService(sling *sling.Sling) *Service { 19 | return &Service{ 20 | sling: sling.New().Path(basePath), 21 | } 22 | } 23 | 24 | // Create passes credentials and returns a token 25 | func (s *Service) Create(r *CreateRequest) (*AuthToken, error) { 26 | token := new(AuthToken) 27 | apierr := new(errors.APIError) 28 | _, err := s.sling.New().Post("").BodyJSON(r).Receive(token, apierr) 29 | return token, errors.BuildError(err, apierr) 30 | } 31 | -------------------------------------------------------------------------------- /towerapi/authtoken/authtoken_model.go: -------------------------------------------------------------------------------- 1 | package authtoken 2 | 3 | // AuthToken represents a Ansible Tower AuthToken. 4 | type AuthToken struct { 5 | Token string `json:"token"` 6 | Expires string `json:"expires"` 7 | } 8 | 9 | // AuthTokenCreateRequest represents a request to create a new key. 10 | type CreateRequest struct { 11 | Username string `json:"username"` 12 | Password string `json:"password"` 13 | } 14 | -------------------------------------------------------------------------------- /towerapi/authtoken/authtoken_test.go: -------------------------------------------------------------------------------- 1 | package authtoken 2 | 3 | /* 4 | import ( 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | "reflect" 9 | "testing" 10 | ) 11 | 12 | func TestAuthToken_Create(t *testing.T) { 13 | setup() 14 | defer teardown() 15 | 16 | var aUsername = "admin" 17 | var aPassword string = "admin" 18 | var aToken string = "8f17825cf08a7efea124f2638f3896f6637f8745" 19 | var aExpires string = "2023-09-05T21:46:35.729Z" 20 | 21 | createRequest := &AuthTokenCreateRequest{ 22 | Username: aUsername, 23 | Password: aPassword, 24 | } 25 | 26 | mux.HandleFunc("/authtoken/", func(w http.ResponseWriter, r *http.Request) { 27 | v := new(AuthTokenCreateRequest) 28 | err := json.NewDecoder(r.Body).Decode(v) 29 | if err != nil { 30 | t.Fatalf("decode json: %v", err) 31 | } 32 | 33 | testMethod(t, r, "POST") 34 | if !reflect.DeepEqual(v, createRequest) { 35 | t.Errorf("Request body = %+v, expected %+v", v, createRequest) 36 | } 37 | fmt.Fprintf(w, `{"token":"`+aToken+`","expires":"`+aExpires+`"}"`) 38 | }) 39 | 40 | authToken, _, err := client.AuthToken.Create(createRequest) 41 | if err != nil { 42 | t.Errorf("AuthToken.Create returned error: %v", err) 43 | } 44 | 45 | expected := &AuthToken{ 46 | Token: aToken, 47 | Expires: aExpires, 48 | } 49 | if !reflect.DeepEqual(authToken, expected) { 50 | t.Errorf("AuthToken.Create returned %+v, expected %+v", authToken, expected) 51 | } 52 | } 53 | */ 54 | -------------------------------------------------------------------------------- /towerapi/credentials/credentials.go: -------------------------------------------------------------------------------- 1 | package credentials 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mpeter/go-towerapi/towerapi/errors" 7 | "github.com/mpeter/go-towerapi/towerapi/params" 8 | "github.com/mpeter/sling" 9 | ) 10 | 11 | const basePath = "credentials/" 12 | 13 | // Service is an interface for interfacing with the 14 | // endpoints of the Ansible Tower API 15 | type Service struct { 16 | sling *sling.Sling 17 | } 18 | 19 | // NewService handles communication with auth credential related methods of the 20 | // Ansible Tower API. 21 | func NewService(sling *sling.Sling) *Service { 22 | return &Service{ 23 | sling: sling.Path(basePath), 24 | } 25 | } 26 | 27 | // Create creates a new Credential 28 | func (s *Service) Create(r *Request) (*Credential, error) { 29 | credential := new(Credential) 30 | apierr := new(errors.APIError) 31 | _, err := s.sling.New().Post("").BodyJSON(r).Receive(credential, apierr) 32 | return credential, errors.BuildError(err, apierr) 33 | } 34 | 35 | // Updates modifies an existing credential 36 | func (s *Service) Update(r *Request) (*Credential, error) { 37 | credential := new(Credential) 38 | apierr := new(errors.APIError) 39 | _, err := s.sling.New().Put(r.ID+"/").BodyJSON(r).Receive(credential, apierr) 40 | return credential, errors.BuildError(err, apierr) 41 | } 42 | 43 | func (s *Service) Delete(id string) error { 44 | _, err := s.sling.New().Delete(id + "/").ReceiveSuccess(nil) 45 | return errors.BuildError(err, nil) 46 | } 47 | 48 | func (s *Service) List() ([]Credential, error) { 49 | credentials := new(Credentials) 50 | apierr := new(errors.APIError) 51 | _, err := s.sling.New().Get("").Receive(credentials, apierr) 52 | return credentials.Results, errors.BuildError(err, apierr) 53 | } 54 | 55 | func (s *Service) ListByName(name string) ([]Credential, error) { 56 | credentials := new(Credentials) 57 | apierr := new(errors.APIError) 58 | params := ¶ms.ListParams{Name: name} 59 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(credentials, apierr) 60 | return credentials.Results, errors.BuildError(err, apierr) 61 | } 62 | 63 | func (s *Service) GetByName(name string) (*Credential, error) { 64 | credentials := new(Credentials) 65 | apierr := new(errors.APIError) 66 | 67 | params := ¶ms.ListParams{Name: name} 68 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(credentials, apierr) 69 | if err := errors.BuildError(err, apierr); err != nil { 70 | return nil, err 71 | } 72 | if credentials.Count == 0 { 73 | return nil, nil 74 | } else if credentials.Count > 1 { 75 | return nil, fmt.Errorf("Exact search returned more than 1 result for %s, should never happen", name) 76 | } 77 | results := credentials.Results[0] 78 | return &results, nil 79 | } 80 | 81 | func (s *Service) GetByID(id string) (*Credential, error) { 82 | credential := new(Credential) 83 | apierr := new(errors.APIError) 84 | _, err := s.sling.New().Get(id+"/").Receive(credential, apierr) 85 | return credential, errors.BuildError(err, apierr) 86 | } 87 | -------------------------------------------------------------------------------- /towerapi/credentials/credentials_struct.go: -------------------------------------------------------------------------------- 1 | package credentials 2 | 3 | type Request struct { 4 | ID string `json:"-"` 5 | Name string `json:"name"` 6 | Description string `json:"description"` 7 | Kind string `json:"kind"` 8 | Host string `json:"host"` 9 | Username string `json:"username"` 10 | Password string `json:"password"` 11 | SecurityToken string `json:"security_token"` 12 | Project string `json:"project" mapstructure:"project_id"` 13 | Domain string `json:"domain"` 14 | SSHKeyData string `json:"ssh_key_data"` 15 | SSHKeyUnlock string `json:"ssh_key_unlock"` 16 | Organization *int `json:"organization" mapstructure:"organization_id"` 17 | BecomeMethod string `json:"become_method"` 18 | BecomeUsername string `json:"become_username"` 19 | BecomePassword string `json:"become_password"` 20 | VaultPassword string `json:"vault_password"` 21 | Subscription string `json:"subscription"` 22 | Tenant string `json:"tenant"` 23 | Secret string `json:"secret"` 24 | Client string `json:"client"` 25 | Authorize bool `json:"authorize"` 26 | AuthorizePassword string `json:"authorize_password"` 27 | } 28 | 29 | type Credentials struct { 30 | Count int `json:"count"` 31 | Next string `json:"next"` 32 | Previous string `json:"previous"` 33 | Results []Credential `json:"results"` 34 | } 35 | 36 | type Credential struct { 37 | Authorize bool `json:"authorize"` 38 | AuthorizePassword string `json:"authorize_password"` 39 | BecomeMethod string `json:"become_method"` 40 | BecomePassword string `json:"become_password"` 41 | BecomeUsername string `json:"become_username"` 42 | Client string `json:"client"` 43 | Cloud bool `json:"cloud"` 44 | Created string `json:"created"` 45 | Description string `json:"description"` 46 | Domain string `json:"domain"` 47 | Host string `json:"host"` 48 | ID int `json:"id"` 49 | Kind string `json:"kind"` 50 | Modified string `json:"modified"` 51 | Name string `json:"name"` 52 | Organization *int `json:"organization"` 53 | Password string `json:"password"` 54 | Project string `json:"project"` 55 | Related struct { 56 | AccessList string `json:"access_list"` 57 | ActivityStream string `json:"activity_stream"` 58 | CreatedBy string `json:"created_by"` 59 | ModifiedBy string `json:"modified_by"` 60 | ObjectRoles string `json:"object_roles"` 61 | Organization string `json:"organization"` 62 | OwnerTeams string `json:"owner_teams"` 63 | OwnerUsers string `json:"owner_users"` 64 | } `json:"related"` 65 | Secret string `json:"secret"` 66 | SecurityToken string `json:"security_token"` 67 | SSHKeyData string `json:"ssh_key_data"` 68 | SSHKeyUnlock string `json:"ssh_key_unlock"` 69 | Subscription string `json:"subscription"` 70 | SummaryFields struct { 71 | CreatedBy struct { 72 | FirstName string `json:"first_name"` 73 | ID *int `json:"id"` 74 | LastName string `json:"last_name"` 75 | Username string `json:"username"` 76 | } `json:"created_by"` 77 | Host struct{} `json:"host"` 78 | ModifiedBy struct { 79 | FirstName string `json:"first_name"` 80 | ID *int `json:"id"` 81 | LastName string `json:"last_name"` 82 | Username string `json:"username"` 83 | } `json:"modified_by"` 84 | ObjectRoles struct { 85 | AdminRole struct { 86 | Description string `json:"description"` 87 | ID *int `json:"id"` 88 | Name string `json:"name"` 89 | } `json:"admin_role"` 90 | ReadRole struct { 91 | Description string `json:"description"` 92 | ID *int `json:"id"` 93 | Name string `json:"name"` 94 | } `json:"read_role"` 95 | UseRole struct { 96 | Description string `json:"description"` 97 | ID *int `json:"id"` 98 | Name string `json:"name"` 99 | } `json:"use_role"` 100 | } `json:"object_roles"` 101 | Organization struct { 102 | Description string `json:"description"` 103 | ID *int `json:"id"` 104 | Name string `json:"name"` 105 | } `json:"organization"` 106 | Owners []struct { 107 | Description string `json:"description"` 108 | ID *int `json:"id"` 109 | Name string `json:"name"` 110 | Type string `json:"type"` 111 | URL string `json:"url"` 112 | } `json:"owners"` 113 | Project struct{} `json:"project"` 114 | } `json:"summary_fields"` 115 | Tenant string `json:"tenant"` 116 | Type string `json:"type"` 117 | URL string `json:"url"` 118 | Username string `json:"username"` 119 | VaultPassword string `json:"vault_password"` 120 | } 121 | -------------------------------------------------------------------------------- /towerapi/doc.go: -------------------------------------------------------------------------------- 1 | // Package towerapi is the Ansible Tower API v1 client for Go 2 | package towerapi 3 | -------------------------------------------------------------------------------- /towerapi/errors/error.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/go-multierror" 7 | ) 8 | 9 | // An APIError reports the error caused by an API request 10 | type APIError struct { 11 | Errors []string `json:"__all__,omitempty"` 12 | Detail string `json:"detail,omitempty"` 13 | } 14 | 15 | func (e APIError) Error() string { 16 | var result *multierror.Error 17 | if e.Detail != "" { 18 | result = multierror.Append(result, fmt.Errorf(e.Detail)) 19 | } 20 | for _, err := range e.Errors { 21 | result = multierror.Append(result, fmt.Errorf(err)) 22 | } 23 | if result.ErrorOrNil() != nil { 24 | return result.GoString() 25 | } else { 26 | return "" 27 | } 28 | 29 | } 30 | 31 | // BuildError returns any non-nil http-related error (creating the request, 32 | // getting the response, decoding) if any. If the decoded apierr is non-zero 33 | // the apierr is returned. Otherwise, no errors occurred, returns nil. 34 | func BuildError(httperr error, apierr *APIError) error { 35 | var result *multierror.Error 36 | if httperr != nil { 37 | result = multierror.Append(result, httperr) 38 | } 39 | return result.ErrorOrNil() 40 | } 41 | -------------------------------------------------------------------------------- /towerapi/groups/groups.go: -------------------------------------------------------------------------------- 1 | package groups 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mpeter/go-towerapi/towerapi/errors" 7 | "github.com/mpeter/go-towerapi/towerapi/params" 8 | "github.com/mpeter/sling" 9 | ) 10 | 11 | const basePath = "groups/" 12 | 13 | // Service is an interface for interfacing with the 14 | // endpoints of the Ansible Tower API 15 | type Service struct { 16 | sling *sling.Sling 17 | } 18 | 19 | // NewService handles communication with auth group related methods of the 20 | // Ansible Tower API. 21 | func NewService(sling *sling.Sling) *Service { 22 | return &Service{ 23 | sling: sling.Path(basePath), 24 | } 25 | } 26 | 27 | // Create creates a new Group 28 | func (s *Service) Create(r *Request) (*Group, error) { 29 | group := new(Group) 30 | apierr := new(errors.APIError) 31 | _, err := s.sling.New().Post("").BodyJSON(r).Receive(group, apierr) 32 | return group, errors.BuildError(err, apierr) 33 | } 34 | 35 | // Updates modifies an existing group 36 | func (s *Service) Update(r *Request) (*Group, error) { 37 | group := new(Group) 38 | apierr := new(errors.APIError) 39 | _, err := s.sling.New().Put(r.ID+"/").BodyJSON(r).Receive(group, apierr) 40 | return group, errors.BuildError(err, apierr) 41 | } 42 | 43 | func (s *Service) Delete(id string) error { 44 | _, err := s.sling.New().Delete(id + "/").ReceiveSuccess(nil) 45 | return errors.BuildError(err, nil) 46 | } 47 | 48 | func (s *Service) List() ([]Group, error) { 49 | groups := new(Groups) 50 | apierr := new(errors.APIError) 51 | _, err := s.sling.New().Get("").Receive(groups, apierr) 52 | return groups.Results, errors.BuildError(err, apierr) 53 | } 54 | 55 | func (s *Service) ListByName(name string) ([]Group, error) { 56 | groups := new(Groups) 57 | apierr := new(errors.APIError) 58 | params := ¶ms.ListParams{Name: name} 59 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(groups, apierr) 60 | return groups.Results, errors.BuildError(err, apierr) 61 | } 62 | 63 | func (s *Service) GetByName(name string) (*Group, error) { 64 | groups := new(Groups) 65 | apierr := new(errors.APIError) 66 | 67 | params := ¶ms.ListParams{Name: name} 68 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(groups, apierr) 69 | if err := errors.BuildError(err, apierr); err != nil { 70 | return nil, err 71 | } 72 | if groups.Count == 0 { 73 | return nil, nil 74 | } else if groups.Count > 1 { 75 | return nil, fmt.Errorf("Exact search returned more than 1 result for %s, should never happen", name) 76 | } 77 | results := groups.Results[0] 78 | return &results, nil 79 | } 80 | 81 | func (s *Service) GetByID(id string) (*Group, error) { 82 | group := new(Group) 83 | apierr := new(errors.APIError) 84 | _, err := s.sling.New().Get(id+"/").Receive(group, apierr) 85 | return group, errors.BuildError(err, apierr) 86 | } 87 | -------------------------------------------------------------------------------- /towerapi/groups/groups_struct.go: -------------------------------------------------------------------------------- 1 | package groups 2 | 3 | type Request struct { 4 | ID string `json:"-"` 5 | Name string `json:"name"` 6 | Description string `json:"description"` 7 | Inventory *int `json:"inventory"` 8 | Variables string `json:"variables" yaml:"variables"` 9 | } 10 | 11 | type Groups struct { 12 | Count int `json:"count"` 13 | Next string `json:"next"` 14 | Previous string `json:"previous"` 15 | Results []Group `json:"results"` 16 | } 17 | 18 | type Group struct { 19 | Created string `json:"created"` 20 | Description string `json:"description"` 21 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 22 | HasActiveFailures bool `json:"has_active_failures"` 23 | HasInventorySources bool `json:"has_inventory_sources"` 24 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 25 | ID int `json:"id"` 26 | Inventory int `json:"inventory"` 27 | Modified string `json:"modified"` 28 | Name string `json:"name"` 29 | Related struct { 30 | ActivityStream string `json:"activity_stream"` 31 | AdHocCommands string `json:"ad_hoc_commands"` 32 | AllHosts string `json:"all_hosts"` 33 | Children string `json:"children"` 34 | CreatedBy string `json:"created_by"` 35 | Hosts string `json:"hosts"` 36 | Inventory string `json:"inventory"` 37 | InventorySource string `json:"inventory_source"` 38 | InventorySources string `json:"inventory_sources"` 39 | JobEvents string `json:"job_events"` 40 | JobHostSummaries string `json:"job_host_summaries"` 41 | PotentialChildren string `json:"potential_children"` 42 | VariableData string `json:"variable_data"` 43 | } `json:"related"` 44 | SummaryFields struct { 45 | CreatedBy struct { 46 | FirstName string `json:"first_name"` 47 | ID int `json:"id"` 48 | LastName string `json:"last_name"` 49 | Username string `json:"username"` 50 | } `json:"created_by"` 51 | Inventory struct { 52 | Description string `json:"description"` 53 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 54 | HasActiveFailures bool `json:"has_active_failures"` 55 | HasInventorySources bool `json:"has_inventory_sources"` 56 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 57 | ID int `json:"id"` 58 | InventorySourcesWithFailures int `json:"inventory_sources_with_failures"` 59 | Name string `json:"name"` 60 | TotalGroups int `json:"total_groups"` 61 | TotalHosts int `json:"total_hosts"` 62 | TotalInventorySources int `json:"total_inventory_sources"` 63 | } `json:"inventory"` 64 | InventorySource struct { 65 | Source string `json:"source"` 66 | Status string `json:"status"` 67 | } `json:"inventory_source"` 68 | } `json:"summary_fields"` 69 | TotalGroups int `json:"total_groups"` 70 | TotalHosts int `json:"total_hosts"` 71 | Type string `json:"type"` 72 | URL string `json:"url"` 73 | Variables string `json:"variables"` 74 | } 75 | -------------------------------------------------------------------------------- /towerapi/hosts/hosts.go: -------------------------------------------------------------------------------- 1 | package hosts 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mpeter/go-towerapi/towerapi/errors" 7 | "github.com/mpeter/go-towerapi/towerapi/params" 8 | "github.com/mpeter/sling" 9 | ) 10 | 11 | const basePath = "hosts/" 12 | 13 | // Service is an interface for interfacing with the 14 | // endpoints of the Ansible Tower API 15 | type Service struct { 16 | sling *sling.Sling 17 | } 18 | 19 | // NewService handles communication with auth host related methods of the 20 | // Ansible Tower API. 21 | func NewService(sling *sling.Sling) *Service { 22 | return &Service{ 23 | sling: sling.Path(basePath), 24 | } 25 | } 26 | 27 | // Create creates a new Host 28 | func (s *Service) Create(r *Request) (*Host, error) { 29 | host := new(Host) 30 | apierr := new(errors.APIError) 31 | _, err := s.sling.New().Post("").BodyJSON(r).Receive(host, apierr) 32 | return host, errors.BuildError(err, apierr) 33 | } 34 | 35 | // Updates modifies an existing host 36 | func (s *Service) Update(r *Request) (*Host, error) { 37 | host := new(Host) 38 | apierr := new(errors.APIError) 39 | _, err := s.sling.New().Put(r.ID+"/").BodyJSON(r).Receive(host, apierr) 40 | return host, errors.BuildError(err, apierr) 41 | } 42 | 43 | func (s *Service) Delete(id string) error { 44 | _, err := s.sling.New().Delete(id + "/").ReceiveSuccess(nil) 45 | return errors.BuildError(err, nil) 46 | } 47 | 48 | func (s *Service) List() ([]Host, error) { 49 | hosts := new(Hosts) 50 | apierr := new(errors.APIError) 51 | _, err := s.sling.New().Get("").Receive(hosts, apierr) 52 | return hosts.Results, errors.BuildError(err, apierr) 53 | } 54 | 55 | func (s *Service) ListByName(name string) ([]Host, error) { 56 | hosts := new(Hosts) 57 | apierr := new(errors.APIError) 58 | params := ¶ms.ListParams{Name: name} 59 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(hosts, apierr) 60 | return hosts.Results, errors.BuildError(err, apierr) 61 | } 62 | 63 | func (s *Service) GetByName(name string) (*Host, error) { 64 | hosts := new(Hosts) 65 | apierr := new(errors.APIError) 66 | 67 | params := ¶ms.ListParams{Name: name} 68 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(hosts, apierr) 69 | if err := errors.BuildError(err, apierr); err != nil { 70 | return nil, err 71 | } 72 | if hosts.Count == 0 { 73 | return nil, nil 74 | } else if hosts.Count > 1 { 75 | return nil, fmt.Errorf("Exact search returned more than 1 result for %s, should never happen", name) 76 | } 77 | results := &hosts.Results[0] 78 | return results, nil 79 | } 80 | 81 | func (s *Service) GetByID(id string) (*Host, error) { 82 | host := new(Host) 83 | apierr := new(errors.APIError) 84 | _, err := s.sling.New().Get(id+"/").Receive(host, apierr) 85 | return host, errors.BuildError(err, apierr) 86 | } 87 | -------------------------------------------------------------------------------- /towerapi/hosts/hosts_struct.go: -------------------------------------------------------------------------------- 1 | package hosts 2 | 3 | type Request struct { 4 | ID string `json:"-"` 5 | Name string `json:"name"` 6 | Description string `json:"description"` 7 | Inventory *int `json:"inventory"` 8 | Enabled bool `json:"enabled"` 9 | InstanceID string `json:"instance_id"` 10 | Variables string `json:"variables" yaml:"variables"` 11 | } 12 | 13 | type Hosts struct { 14 | Count int `json:"count"` 15 | Next string `json:"next"` 16 | Previous string `json:"previous"` 17 | Results []Host `json:"results"` 18 | } 19 | 20 | type Host struct { 21 | Created string `json:"created"` 22 | Description string `json:"description"` 23 | Enabled bool `json:"enabled"` 24 | HasActiveFailures bool `json:"has_active_failures"` 25 | HasInventorySources bool `json:"has_inventory_sources"` 26 | ID int `json:"id"` 27 | InstanceID string `json:"instance_id"` 28 | Inventory int `json:"inventory"` 29 | LastJob int `json:"last_job"` 30 | LastJobHostSummary int `json:"last_job_host_summary"` 31 | Modified string `json:"modified"` 32 | Name string `json:"name"` 33 | Related struct { 34 | ActivityStream string `json:"activity_stream"` 35 | AdHocCommandEvents string `json:"ad_hoc_command_events"` 36 | AdHocCommands string `json:"ad_hoc_commands"` 37 | AllGroups string `json:"all_groups"` 38 | CreatedBy string `json:"created_by"` 39 | FactVersions string `json:"fact_versions"` 40 | Groups string `json:"groups"` 41 | Inventory string `json:"inventory"` 42 | InventorySources string `json:"inventory_sources"` 43 | JobEvents string `json:"job_events"` 44 | JobHostSummaries string `json:"job_host_summaries"` 45 | LastJob string `json:"last_job"` 46 | LastJobHostSummary string `json:"last_job_host_summary"` 47 | ModifiedBy string `json:"modified_by"` 48 | VariableData string `json:"variable_data"` 49 | } `json:"related"` 50 | SummaryFields struct { 51 | CreatedBy struct { 52 | FirstName string `json:"first_name"` 53 | ID int `json:"id"` 54 | LastName string `json:"last_name"` 55 | Username string `json:"username"` 56 | } `json:"created_by"` 57 | Inventory struct { 58 | Description string `json:"description"` 59 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 60 | HasActiveFailures bool `json:"has_active_failures"` 61 | HasInventorySources bool `json:"has_inventory_sources"` 62 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 63 | ID int `json:"id"` 64 | InventorySourcesWithFailures int `json:"inventory_sources_with_failures"` 65 | Name string `json:"name"` 66 | TotalGroups int `json:"total_groups"` 67 | TotalHosts int `json:"total_hosts"` 68 | TotalInventorySources int `json:"total_inventory_sources"` 69 | } `json:"inventory"` 70 | LastJob struct { 71 | Description string `json:"description"` 72 | Failed bool `json:"failed"` 73 | Finished string `json:"finished"` 74 | ID int `json:"id"` 75 | JobTemplateID int `json:"job_template_id"` 76 | JobTemplateName string `json:"job_template_name"` 77 | Name string `json:"name"` 78 | Status string `json:"status"` 79 | } `json:"last_job"` 80 | LastJobHostSummary struct { 81 | Failed bool `json:"failed"` 82 | ID int `json:"id"` 83 | } `json:"last_job_host_summary"` 84 | ModifiedBy struct { 85 | FirstName string `json:"first_name"` 86 | ID int `json:"id"` 87 | LastName string `json:"last_name"` 88 | Username string `json:"username"` 89 | } `json:"modified_by"` 90 | RecentJobs []struct { 91 | Finished string `json:"finished"` 92 | ID int `json:"id"` 93 | Name string `json:"name"` 94 | Status string `json:"status"` 95 | } `json:"recent_jobs"` 96 | } `json:"summary_fields"` 97 | Type string `json:"type"` 98 | URL string `json:"url"` 99 | Variables string `json:"variables"` 100 | } 101 | -------------------------------------------------------------------------------- /towerapi/inventories/inventories.go: -------------------------------------------------------------------------------- 1 | package inventories 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mpeter/go-towerapi/towerapi/errors" 7 | "github.com/mpeter/go-towerapi/towerapi/params" 8 | "github.com/mpeter/sling" 9 | ) 10 | 11 | const basePath = "inventories/" 12 | 13 | // Service is an interface for interfacing with the 14 | // endpoints of the Ansible Tower API 15 | type Service struct { 16 | sling *sling.Sling 17 | } 18 | 19 | // NewService handles communication with auth inventory related methods of the 20 | // Ansible Tower API. 21 | func NewService(sling *sling.Sling) *Service { 22 | return &Service{ 23 | sling: sling.Path(basePath), 24 | } 25 | } 26 | 27 | // Create creates a new Inventory 28 | func (s *Service) Create(r *Request) (*Inventory, error) { 29 | inventory := new(Inventory) 30 | apierr := new(errors.APIError) 31 | _, err := s.sling.New().Post("").BodyJSON(r).Receive(inventory, apierr) 32 | return inventory, errors.BuildError(err, apierr) 33 | } 34 | 35 | // Updates modifies an existing inventory 36 | func (s *Service) Update(r *Request) (*Inventory, error) { 37 | inventory := new(Inventory) 38 | apierr := new(errors.APIError) 39 | _, err := s.sling.New().Put(r.ID+"/").BodyJSON(r).Receive(inventory, apierr) 40 | return inventory, errors.BuildError(err, apierr) 41 | } 42 | 43 | func (s *Service) Delete(id string) error { 44 | _, err := s.sling.New().Delete(id + "/").ReceiveSuccess(nil) 45 | return errors.BuildError(err, nil) 46 | } 47 | 48 | func (s *Service) List() ([]Inventory, error) { 49 | inventories := new(Inventories) 50 | apierr := new(errors.APIError) 51 | _, err := s.sling.New().Get("").Receive(inventories, apierr) 52 | return inventories.Results, errors.BuildError(err, apierr) 53 | } 54 | 55 | func (s *Service) ListByName(name string) ([]Inventory, error) { 56 | inventories := new(Inventories) 57 | apierr := new(errors.APIError) 58 | params := ¶ms.ListParams{Name: name} 59 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(inventories, apierr) 60 | return inventories.Results, errors.BuildError(err, apierr) 61 | } 62 | 63 | func (s *Service) GetByName(name string) (*Inventory, error) { 64 | inventories := new(Inventories) 65 | apierr := new(errors.APIError) 66 | 67 | params := ¶ms.ListParams{Name: name} 68 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(inventories, apierr) 69 | if err := errors.BuildError(err, apierr); err != nil { 70 | return nil, err 71 | } 72 | if inventories.Count == 0 { 73 | return nil, nil 74 | } else if inventories.Count > 1 { 75 | return nil, fmt.Errorf("Exact search returned more than 1 result for %s, should never happen", name) 76 | } 77 | results := inventories.Results[0] 78 | return &results, nil 79 | } 80 | 81 | func (s *Service) GetByID(id string) (*Inventory, error) { 82 | inventory := new(Inventory) 83 | apierr := new(errors.APIError) 84 | _, err := s.sling.New().Get(id+"/").Receive(inventory, apierr) 85 | return inventory, errors.BuildError(err, apierr) 86 | } 87 | -------------------------------------------------------------------------------- /towerapi/inventories/inventories_struct.go: -------------------------------------------------------------------------------- 1 | package inventories 2 | 3 | // Request represents a request to create a new key. 4 | type Request struct { 5 | ID string `json:"-"` 6 | Name string `json:"name"` 7 | Description string `json:"description"` 8 | Organization *int `json:"organization"` 9 | Variables string `json:"variables" yaml:"variables"` 10 | } 11 | 12 | type Inventories struct { 13 | Count int `json:"count"` 14 | Next string `json:"next"` 15 | Previous string `json:"previous"` 16 | Results []Inventory `json:"results"` 17 | } 18 | 19 | type Inventory struct { 20 | CanRunAdHocCommands bool `json:"can_run_ad_hoc_commands"` 21 | Created string `json:"created"` 22 | Description string `json:"description"` 23 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 24 | HasActiveFailures bool `json:"has_active_failures"` 25 | HasInventorySources bool `json:"has_inventory_sources"` 26 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 27 | ID int `json:"id"` 28 | InventorySourcesWithFailures int `json:"inventory_sources_with_failures"` 29 | Modified string `json:"modified"` 30 | Name string `json:"name"` 31 | Organization int `json:"organization"` 32 | Related struct { 33 | AccessList string `json:"access_list"` 34 | ActivityStream string `json:"activity_stream"` 35 | AdHocCommands string `json:"ad_hoc_commands"` 36 | CreatedBy string `json:"created_by"` 37 | Groups string `json:"groups"` 38 | Hosts string `json:"hosts"` 39 | InventorySources string `json:"inventory_sources"` 40 | JobTemplates string `json:"job_templates"` 41 | ObjectRoles string `json:"object_roles"` 42 | Organization string `json:"organization"` 43 | RootGroups string `json:"root_groups"` 44 | ScanJobTemplates string `json:"scan_job_templates"` 45 | Script string `json:"script"` 46 | Tree string `json:"tree"` 47 | VariableData string `json:"variable_data"` 48 | } `json:"related"` 49 | SummaryFields struct { 50 | CreatedBy struct { 51 | FirstName string `json:"first_name"` 52 | ID int `json:"id"` 53 | LastName string `json:"last_name"` 54 | Username string `json:"username"` 55 | } `json:"created_by"` 56 | ObjectRoles struct { 57 | AdhocRole struct { 58 | Description string `json:"description"` 59 | ID int `json:"id"` 60 | Name string `json:"name"` 61 | } `json:"adhoc_role"` 62 | AdminRole struct { 63 | Description string `json:"description"` 64 | ID int `json:"id"` 65 | Name string `json:"name"` 66 | } `json:"admin_role"` 67 | ReadRole struct { 68 | Description string `json:"description"` 69 | ID int `json:"id"` 70 | Name string `json:"name"` 71 | } `json:"read_role"` 72 | UpdateRole struct { 73 | Description string `json:"description"` 74 | ID int `json:"id"` 75 | Name string `json:"name"` 76 | } `json:"update_role"` 77 | UseRole struct { 78 | Description string `json:"description"` 79 | ID int `json:"id"` 80 | Name string `json:"name"` 81 | } `json:"use_role"` 82 | } `json:"object_roles"` 83 | Organization struct { 84 | Description string `json:"description"` 85 | ID int `json:"id"` 86 | Name string `json:"name"` 87 | } `json:"organization"` 88 | } `json:"summary_fields"` 89 | TotalGroups int `json:"total_groups"` 90 | TotalHosts int `json:"total_hosts"` 91 | TotalInventorySources int `json:"total_inventory_sources"` 92 | Type string `json:"type"` 93 | URL string `json:"url"` 94 | Variables string `json:"variables" yaml:"variables"` 95 | } 96 | -------------------------------------------------------------------------------- /towerapi/job_templates/job_templates.go: -------------------------------------------------------------------------------- 1 | package job_templates 2 | 3 | import ( 4 | "fmt" 5 | 6 | "reflect" 7 | 8 | "github.com/mpeter/go-towerapi/towerapi/errors" 9 | "github.com/mpeter/go-towerapi/towerapi/params" 10 | "github.com/mpeter/sling" 11 | ) 12 | 13 | const basePath = "job_templates/" 14 | 15 | // Service is an interface for interfacing with the 16 | // endpoints of the Ansible Tower API 17 | type Service struct { 18 | sling *sling.Sling 19 | } 20 | 21 | // NewService handles communication with auth job_template related methods of the 22 | // Ansible Tower API. 23 | func NewService(sling *sling.Sling) *Service { 24 | return &Service{ 25 | sling: sling.Path(basePath), 26 | } 27 | } 28 | 29 | // Create creates a new JobTemplate 30 | func create(s *sling.Sling, r interface{}, suc interface{}) (success interface{}, failure error) { 31 | result := reflect.New(reflect.TypeOf(success)) 32 | apierr := new(errors.APIError) 33 | _, err := s.New().Post("").BodyJSON(r).Receive(result, apierr) 34 | return success, errors.BuildError(err, apierr).(error) 35 | } 36 | 37 | // Create creates a new JobTemplate 38 | func (s *Service) Create(r *Request) (success *JobTemplate, e error) { 39 | //if res,err := create(s.sling, r, success) ; err != nil { 40 | // return nil, err 41 | //} else { 42 | // return res.(*JobTemplate), nil 43 | //} 44 | 45 | job_template := new(JobTemplate) 46 | apierr := new(errors.APIError) 47 | _, err := s.sling.New().Post("").BodyJSON(r).Receive(job_template, apierr) 48 | return job_template, errors.BuildError(err, apierr) 49 | } 50 | 51 | // Updates modifies an existing job_template 52 | func (s *Service) Update(r *Request) (*JobTemplate, error) { 53 | job_template := new(JobTemplate) 54 | apierr := new(errors.APIError) 55 | _, err := s.sling.New().Put(r.ID+"/").BodyJSON(r).Receive(job_template, apierr) 56 | return job_template, errors.BuildError(err, apierr) 57 | } 58 | 59 | func (s *Service) Delete(id string) error { 60 | _, err := s.sling.New().Delete(id + "/").ReceiveSuccess(nil) 61 | return errors.BuildError(err, nil) 62 | } 63 | 64 | func (s *Service) List() ([]JobTemplate, error) { 65 | job_templates := new(JobTemplates) 66 | apierr := new(errors.APIError) 67 | _, err := s.sling.New().Get("").Receive(job_templates, apierr) 68 | return job_templates.Results, errors.BuildError(err, apierr) 69 | } 70 | 71 | func (s *Service) ListByName(name string) ([]JobTemplate, error) { 72 | job_templates := new(JobTemplates) 73 | apierr := new(errors.APIError) 74 | params := ¶ms.ListParams{Name: name} 75 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(job_templates, apierr) 76 | return job_templates.Results, errors.BuildError(err, apierr) 77 | } 78 | 79 | func (s *Service) GetByName(name string) (*JobTemplate, error) { 80 | job_templates := new(JobTemplates) 81 | apierr := new(errors.APIError) 82 | 83 | params := ¶ms.ListParams{Name: name} 84 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(job_templates, apierr) 85 | if err := errors.BuildError(err, apierr); err != nil { 86 | return nil, err 87 | } 88 | if job_templates.Count == 0 { 89 | return nil, nil 90 | } else if job_templates.Count > 1 { 91 | return nil, fmt.Errorf("Exact search returned more than 1 result for %s, should never happen", name) 92 | } 93 | results := &job_templates.Results[0] 94 | return results, nil 95 | } 96 | 97 | func (s *Service) GetByID(id string) (*JobTemplate, error) { 98 | job_template := new(JobTemplate) 99 | apierr := new(errors.APIError) 100 | _, err := s.sling.New().Get(id+"/").Receive(job_template, apierr) 101 | return job_template, errors.BuildError(err, apierr) 102 | } 103 | -------------------------------------------------------------------------------- /towerapi/job_templates/job_templates_struct.go: -------------------------------------------------------------------------------- 1 | package job_templates 2 | 3 | type Request struct { 4 | ID string `json:"-"` 5 | Name string `json:"name"` 6 | Description string `json:"description"` 7 | JobType string `json:"job_type"` 8 | Inventory *int `json:"inventory"` 9 | Project *int `json:"project"` 10 | Playbook string `json:"playbook"` 11 | Credential *int `json:"credential"` 12 | CloudCredential *int `json:"cloud_credential"` 13 | NetworkCredential *int `json:"network_credential"` 14 | Forks int `json:"forks"` 15 | Limit string `json:"limit"` 16 | Verbosity int `json:"verbosity"` 17 | ExtraVars string `json:"extra_vars"` 18 | JobTags string `json:"job_tags"` 19 | ForceHandlers bool `json:"force_handlers"` 20 | SkipTags string `json:"skip_tags"` 21 | StartAtTask string `json:"start_at_task"` 22 | HostConfigKey string `json:"host_config_key"` 23 | AskVariablesOnLaunch bool `json:"ask_variables_on_launch"` 24 | AskLimitOnLaunch bool `json:"ask_limit_on_launch"` 25 | AskTagsOnLaunch bool `json:"ask_tags_on_launch"` 26 | AskSkipTagsOnLaunch bool `json:"ask_skip_tags_on_launch"` 27 | AskJobTypeOnLaunch bool `json:"ask_job_type_on_launch"` 28 | AskCredentialOnLaunch bool `json:"ask_credential_on_launch"` 29 | SurveyEnabled bool `json:"survey_enabled"` 30 | AllowSimultaneous bool `json:"allow_simultaneous"` 31 | } 32 | 33 | type JobTemplates struct { 34 | Count int `json:"count"` 35 | Next string `json:"next"` 36 | Previous string `json:"previous"` 37 | Results []JobTemplate `json:"results"` 38 | } 39 | 40 | type JobTemplate struct { 41 | AllowSimultaneous bool `json:"allow_simultaneous"` 42 | AskCredentialOnLaunch bool `json:"ask_credential_on_launch"` 43 | AskInventoryOnLaunch bool `json:"ask_inventory_on_launch"` 44 | AskJobTypeOnLaunch bool `json:"ask_job_type_on_launch"` 45 | AskLimitOnLaunch bool `json:"ask_limit_on_launch"` 46 | AskSkipTagsOnLaunch bool `json:"ask_skip_tags_on_launch"` 47 | AskTagsOnLaunch bool `json:"ask_tags_on_launch"` 48 | AskVariablesOnLaunch bool `json:"ask_variables_on_launch"` 49 | BecomeEnabled bool `json:"become_enabled"` 50 | CloudCredential *int `json:"cloud_credential"` 51 | Created string `json:"created"` 52 | Credential *int `json:"credential"` 53 | Description string `json:"description"` 54 | ExtraVars string `json:"extra_vars"` 55 | ForceHandlers bool `json:"force_handlers"` 56 | Forks int `json:"forks"` 57 | HasSchedules bool `json:"has_schedules"` 58 | HostConfigKey string `json:"host_config_key"` 59 | ID int `json:"id"` 60 | Inventory *int `json:"inventory"` 61 | JobTags string `json:"job_tags"` 62 | JobType string `json:"job_type"` 63 | LastJobFailed bool `json:"last_job_failed"` 64 | LastJobRun string `json:"last_job_run"` 65 | Limit string `json:"limit"` 66 | Modified string `json:"modified"` 67 | Name string `json:"name"` 68 | NetworkCredential *int `json:"network_credential"` 69 | NextJobRun string `json:"next_job_run"` 70 | Playbook string `json:"playbook"` 71 | Project *int `json:"project"` 72 | Related struct { 73 | AccessList string `json:"access_list"` 74 | ActivityStream string `json:"activity_stream"` 75 | Callback string `json:"callback"` 76 | CloudCredential string `json:"cloud_credential"` 77 | CreatedBy string `json:"created_by"` 78 | Credential string `json:"credential"` 79 | Inventory string `json:"inventory"` 80 | Jobs string `json:"jobs"` 81 | Labels string `json:"labels"` 82 | LastJob string `json:"last_job"` 83 | Launch string `json:"launch"` 84 | ModifiedBy string `json:"modified_by"` 85 | NetworkCredential string `json:"network_credential"` 86 | NotificationTemplatesAny string `json:"notification_templates_any"` 87 | NotificationTemplatesError string `json:"notification_templates_error"` 88 | NotificationTemplatesSuccess string `json:"notification_templates_success"` 89 | ObjectRoles string `json:"object_roles"` 90 | Project string `json:"project"` 91 | Schedules string `json:"schedules"` 92 | SurveySpec string `json:"survey_spec"` 93 | } `json:"related"` 94 | SkipTags string `json:"skip_tags"` 95 | StartAtTask string `json:"start_at_task"` 96 | Status string `json:"status"` 97 | SummaryFields struct { 98 | CanCopy bool `json:"can_copy"` 99 | CanEdit bool `json:"can_edit"` 100 | CloudCredential struct { 101 | Cloud bool `json:"cloud"` 102 | Description string `json:"description"` 103 | ID int `json:"id"` 104 | Kind string `json:"kind"` 105 | Name string `json:"name"` 106 | } `json:"cloud_credential"` 107 | CreatedBy struct { 108 | FirstName string `json:"first_name"` 109 | ID int `json:"id"` 110 | LastName string `json:"last_name"` 111 | Username string `json:"username"` 112 | } `json:"created_by"` 113 | Credential struct { 114 | Cloud bool `json:"cloud"` 115 | Description string `json:"description"` 116 | ID int `json:"id"` 117 | Kind string `json:"kind"` 118 | Name string `json:"name"` 119 | } `json:"credential"` 120 | Inventory struct { 121 | Description string `json:"description"` 122 | GroupsWithActiveFailures int `json:"groups_with_active_failures"` 123 | HasActiveFailures bool `json:"has_active_failures"` 124 | HasInventorySources bool `json:"has_inventory_sources"` 125 | HostsWithActiveFailures int `json:"hosts_with_active_failures"` 126 | ID int `json:"id"` 127 | InventorySourcesWithFailures int `json:"inventory_sources_with_failures"` 128 | Name string `json:"name"` 129 | TotalGroups int `json:"total_groups"` 130 | TotalHosts int `json:"total_hosts"` 131 | TotalInventorySources int `json:"total_inventory_sources"` 132 | } `json:"inventory"` 133 | Labels struct { 134 | Count int `json:"count"` 135 | Results []struct { 136 | ID int `json:"id"` 137 | Name string `json:"name"` 138 | } `json:"results"` 139 | } `json:"labels"` 140 | LastJob struct { 141 | Description string `json:"description"` 142 | Failed bool `json:"failed"` 143 | Finished string `json:"finished"` 144 | ID int `json:"id"` 145 | Name string `json:"name"` 146 | Status string `json:"status"` 147 | } `json:"last_job"` 148 | LastUpdate struct { 149 | Description string `json:"description"` 150 | Failed bool `json:"failed"` 151 | ID int `json:"id"` 152 | Name string `json:"name"` 153 | Status string `json:"status"` 154 | } `json:"last_update"` 155 | ModifiedBy struct { 156 | FirstName string `json:"first_name"` 157 | ID int `json:"id"` 158 | LastName string `json:"last_name"` 159 | Username string `json:"username"` 160 | } `json:"modified_by"` 161 | NetworkCredential struct { 162 | Description string `json:"description"` 163 | ID int `json:"id"` 164 | Kind string `json:"kind"` 165 | Name string `json:"name"` 166 | } `json:"network_credential"` 167 | ObjectRoles struct { 168 | AdminRole struct { 169 | Description string `json:"description"` 170 | ID int `json:"id"` 171 | Name string `json:"name"` 172 | } `json:"admin_role"` 173 | ExecuteRole struct { 174 | Description string `json:"description"` 175 | ID int `json:"id"` 176 | Name string `json:"name"` 177 | } `json:"execute_role"` 178 | ReadRole struct { 179 | Description string `json:"description"` 180 | ID int `json:"id"` 181 | Name string `json:"name"` 182 | } `json:"read_role"` 183 | } `json:"object_roles"` 184 | Project struct { 185 | Description string `json:"description"` 186 | ID int `json:"id"` 187 | Name string `json:"name"` 188 | Status string `json:"status"` 189 | } `json:"project"` 190 | RecentJobs []struct { 191 | Finished string `json:"finished"` 192 | ID int `json:"id"` 193 | Status string `json:"status"` 194 | } `json:"recent_jobs"` 195 | } `json:"summary_fields"` 196 | SurveyEnabled bool `json:"survey_enabled"` 197 | Type string `json:"type"` 198 | URL string `json:"url"` 199 | Verbosity int `json:"verbosity"` 200 | } 201 | -------------------------------------------------------------------------------- /towerapi/job_templates/job_templates_test.go: -------------------------------------------------------------------------------- 1 | package job_templates 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/mpeter/sling" 8 | ) 9 | 10 | func TestNewService(t *testing.T) { 11 | type args struct { 12 | sling *sling.Sling 13 | } 14 | tests := []struct { 15 | name string 16 | args args 17 | want *Service 18 | }{ 19 | // TODO: Add test cases. 20 | } 21 | for _, tt := range tests { 22 | if got := NewService(tt.args.sling); !reflect.DeepEqual(got, tt.want) { 23 | t.Errorf("%q. NewService() = %v, want %v", tt.name, got, tt.want) 24 | } 25 | } 26 | } 27 | 28 | func TestService_Create(t *testing.T) { 29 | type fields struct { 30 | sling *sling.Sling 31 | } 32 | type args struct { 33 | r *Request 34 | } 35 | tests := []struct { 36 | name string 37 | fields fields 38 | args args 39 | want *JobTemplate 40 | wantErr bool 41 | }{ 42 | // TODO: Add test cases. 43 | } 44 | for _, tt := range tests { 45 | s := &Service{ 46 | sling: tt.fields.sling, 47 | } 48 | got, err := s.Create(tt.args.r) 49 | if (err != nil) != tt.wantErr { 50 | t.Errorf("%q. Service.Create() error = %v, wantErr %v", tt.name, err, tt.wantErr) 51 | continue 52 | } 53 | if !reflect.DeepEqual(got, tt.want) { 54 | t.Errorf("%q. Service.Create() = %v, want %v", tt.name, got, tt.want) 55 | } 56 | } 57 | } 58 | 59 | func TestService_Update(t *testing.T) { 60 | type fields struct { 61 | sling *sling.Sling 62 | } 63 | type args struct { 64 | r *Request 65 | } 66 | tests := []struct { 67 | name string 68 | fields fields 69 | args args 70 | want *JobTemplate 71 | wantErr bool 72 | }{ 73 | // TODO: Add test cases. 74 | } 75 | for _, tt := range tests { 76 | s := &Service{ 77 | sling: tt.fields.sling, 78 | } 79 | got, err := s.Update(tt.args.r) 80 | if (err != nil) != tt.wantErr { 81 | t.Errorf("%q. Service.Update() error = %v, wantErr %v", tt.name, err, tt.wantErr) 82 | continue 83 | } 84 | if !reflect.DeepEqual(got, tt.want) { 85 | t.Errorf("%q. Service.Update() = %v, want %v", tt.name, got, tt.want) 86 | } 87 | } 88 | } 89 | 90 | func TestService_Delete(t *testing.T) { 91 | type fields struct { 92 | sling *sling.Sling 93 | } 94 | type args struct { 95 | id string 96 | } 97 | tests := []struct { 98 | name string 99 | fields fields 100 | args args 101 | wantErr bool 102 | }{ 103 | // TODO: Add test cases. 104 | } 105 | for _, tt := range tests { 106 | s := &Service{ 107 | sling: tt.fields.sling, 108 | } 109 | if err := s.Delete(tt.args.id); (err != nil) != tt.wantErr { 110 | t.Errorf("%q. Service.Delete() error = %v, wantErr %v", tt.name, err, tt.wantErr) 111 | } 112 | } 113 | } 114 | 115 | func TestService_List(t *testing.T) { 116 | type fields struct { 117 | sling *sling.Sling 118 | } 119 | tests := []struct { 120 | name string 121 | fields fields 122 | want []JobTemplate 123 | wantErr bool 124 | }{ 125 | // TODO: Add test cases. 126 | } 127 | for _, tt := range tests { 128 | s := &Service{ 129 | sling: tt.fields.sling, 130 | } 131 | got, err := s.List() 132 | if (err != nil) != tt.wantErr { 133 | t.Errorf("%q. Service.List() error = %v, wantErr %v", tt.name, err, tt.wantErr) 134 | continue 135 | } 136 | if !reflect.DeepEqual(got, tt.want) { 137 | t.Errorf("%q. Service.List() = %v, want %v", tt.name, got, tt.want) 138 | } 139 | } 140 | } 141 | 142 | func TestService_ListByName(t *testing.T) { 143 | type fields struct { 144 | sling *sling.Sling 145 | } 146 | type args struct { 147 | name string 148 | } 149 | tests := []struct { 150 | name string 151 | fields fields 152 | args args 153 | want []JobTemplate 154 | wantErr bool 155 | }{ 156 | // TODO: Add test cases. 157 | } 158 | for _, tt := range tests { 159 | s := &Service{ 160 | sling: tt.fields.sling, 161 | } 162 | got, err := s.ListByName(tt.args.name) 163 | if (err != nil) != tt.wantErr { 164 | t.Errorf("%q. Service.ListByName() error = %v, wantErr %v", tt.name, err, tt.wantErr) 165 | continue 166 | } 167 | if !reflect.DeepEqual(got, tt.want) { 168 | t.Errorf("%q. Service.ListByName() = %v, want %v", tt.name, got, tt.want) 169 | } 170 | } 171 | } 172 | 173 | func TestService_GetByName(t *testing.T) { 174 | type fields struct { 175 | sling *sling.Sling 176 | } 177 | type args struct { 178 | name string 179 | } 180 | tests := []struct { 181 | name string 182 | fields fields 183 | args args 184 | want *JobTemplate 185 | wantErr bool 186 | }{ 187 | // TODO: Add test cases. 188 | } 189 | for _, tt := range tests { 190 | s := &Service{ 191 | sling: tt.fields.sling, 192 | } 193 | got, err := s.GetByName(tt.args.name) 194 | if (err != nil) != tt.wantErr { 195 | t.Errorf("%q. Service.GetByName() error = %v, wantErr %v", tt.name, err, tt.wantErr) 196 | continue 197 | } 198 | if !reflect.DeepEqual(got, tt.want) { 199 | t.Errorf("%q. Service.GetByName() = %v, want %v", tt.name, got, tt.want) 200 | } 201 | } 202 | } 203 | 204 | func TestService_GetByID(t *testing.T) { 205 | type fields struct { 206 | sling *sling.Sling 207 | } 208 | type args struct { 209 | id string 210 | } 211 | tests := []struct { 212 | name string 213 | fields fields 214 | args args 215 | want *JobTemplate 216 | wantErr bool 217 | }{ 218 | // TODO: Add test cases. 219 | } 220 | for _, tt := range tests { 221 | s := &Service{ 222 | sling: tt.fields.sling, 223 | } 224 | got, err := s.GetByID(tt.args.id) 225 | if (err != nil) != tt.wantErr { 226 | t.Errorf("%q. Service.GetByID() error = %v, wantErr %v", tt.name, err, tt.wantErr) 227 | continue 228 | } 229 | if !reflect.DeepEqual(got, tt.want) { 230 | t.Errorf("%q. Service.GetByID() = %v, want %v", tt.name, got, tt.want) 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /towerapi/organizations/organizations.go: -------------------------------------------------------------------------------- 1 | package organizations 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mpeter/go-towerapi/towerapi/errors" 7 | "github.com/mpeter/go-towerapi/towerapi/params" 8 | "github.com/mpeter/sling" 9 | ) 10 | 11 | const basePath = "organizations/" 12 | 13 | // Service is an interface for interfacing with the 14 | // endpoints of the Ansible Tower API 15 | type Service struct { 16 | sling *sling.Sling 17 | } 18 | 19 | // NewService handles communication with auth organization related methods of the 20 | // Ansible Tower API. 21 | func NewService(sling *sling.Sling) *Service { 22 | return &Service{ 23 | sling: sling.Path(basePath), 24 | } 25 | } 26 | 27 | // Create creates a new Organization 28 | func (s *Service) Create(r *Request) (*Organization, error) { 29 | organization := new(Organization) 30 | apierr := new(errors.APIError) 31 | _, err := s.sling.New().Post("").BodyJSON(r).Receive(organization, apierr) 32 | return organization, errors.BuildError(err, apierr) 33 | } 34 | 35 | // Updates modifies an existing organization 36 | func (s *Service) Update(r *Request) (*Organization, error) { 37 | organization := new(Organization) 38 | apierr := new(errors.APIError) 39 | _, err := s.sling.New().Put(r.ID+"/").BodyJSON(r).Receive(organization, apierr) 40 | return organization, errors.BuildError(err, apierr) 41 | } 42 | 43 | func (s *Service) Delete(id string) error { 44 | _, err := s.sling.New().Delete(id + "/").ReceiveSuccess(nil) 45 | return errors.BuildError(err, nil) 46 | } 47 | 48 | func (s *Service) List() ([]Organization, error) { 49 | organizations := new(Organizations) 50 | apierr := new(errors.APIError) 51 | _, err := s.sling.New().Get("").Receive(organizations, apierr) 52 | return organizations.Results, errors.BuildError(err, apierr) 53 | } 54 | 55 | func (s *Service) ListByName(name string) ([]Organization, error) { 56 | organizations := new(Organizations) 57 | apierr := new(errors.APIError) 58 | params := ¶ms.ListParams{Name: name} 59 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(organizations, apierr) 60 | return organizations.Results, errors.BuildError(err, apierr) 61 | } 62 | 63 | func (s *Service) GetByName(name string) (*Organization, error) { 64 | organizations := new(Organizations) 65 | apierr := new(errors.APIError) 66 | 67 | params := ¶ms.ListParams{Name: name} 68 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(organizations, apierr) 69 | if err := errors.BuildError(err, apierr); err != nil { 70 | return nil, err 71 | } 72 | if organizations.Count == 0 { 73 | return nil, nil 74 | } else if organizations.Count > 1 { 75 | return nil, fmt.Errorf("Exact search returned more than 1 result for %s, should never happen", name) 76 | } 77 | results := organizations.Results[0] 78 | return &results, nil 79 | } 80 | 81 | func (s *Service) GetByID(id string) (*Organization, error) { 82 | organization := new(Organization) 83 | apierr := new(errors.APIError) 84 | _, err := s.sling.New().Get(id+"/").Receive(organization, apierr) 85 | return organization, errors.BuildError(err, apierr) 86 | } 87 | -------------------------------------------------------------------------------- /towerapi/organizations/organizations_struct.go: -------------------------------------------------------------------------------- 1 | package organizations 2 | 3 | // Request represents a request to create a new key. 4 | type Request struct { 5 | ID string `json:"-"` 6 | Name string `json:"name"` 7 | Description string `json:"description"` 8 | } 9 | 10 | type Organizations struct { 11 | Count int `json:"count"` 12 | Next string `json:"next"` 13 | Previous string `json:"previous"` 14 | Results []Organization `json:"results"` 15 | } 16 | 17 | type Organization struct { 18 | Created string `json:"created"` 19 | Description string `json:"description"` 20 | ID int `json:"id"` 21 | Modified string `json:"modified"` 22 | Name string `json:"name"` 23 | Related struct { 24 | AccessList string `json:"access_list"` 25 | ActivityStream string `json:"activity_stream"` 26 | Admins string `json:"admins"` 27 | CreatedBy string `json:"created_by"` 28 | Credentials string `json:"credentials"` 29 | Inventories string `json:"inventories"` 30 | ModifiedBy string `json:"modified_by"` 31 | NotificationTemplates string `json:"notification_templates"` 32 | NotificationTemplatesAny string `json:"notification_templates_any"` 33 | NotificationTemplatesError string `json:"notification_templates_error"` 34 | NotificationTemplatesSuccess string `json:"notification_templates_success"` 35 | ObjectRoles string `json:"object_roles"` 36 | Projects string `json:"projects"` 37 | Teams string `json:"teams"` 38 | Users string `json:"users"` 39 | } `json:"related"` 40 | SummaryFields struct { 41 | CreatedBy struct { 42 | FirstName string `json:"first_name"` 43 | ID int `json:"id"` 44 | LastName string `json:"last_name"` 45 | Username string `json:"username"` 46 | } `json:"created_by"` 47 | ModifiedBy struct { 48 | FirstName string `json:"first_name"` 49 | ID int `json:"id"` 50 | LastName string `json:"last_name"` 51 | Username string `json:"username"` 52 | } `json:"modified_by"` 53 | ObjectRoles struct { 54 | AdminRole struct { 55 | Description string `json:"description"` 56 | ID int `json:"id"` 57 | Name string `json:"name"` 58 | } `json:"admin_role"` 59 | AuditorRole struct { 60 | Description string `json:"description"` 61 | ID int `json:"id"` 62 | Name string `json:"name"` 63 | } `json:"auditor_role"` 64 | MemberRole struct { 65 | Description string `json:"description"` 66 | ID int `json:"id"` 67 | Name string `json:"name"` 68 | } `json:"member_role"` 69 | ReadRole struct { 70 | Description string `json:"description"` 71 | ID int `json:"id"` 72 | Name string `json:"name"` 73 | } `json:"read_role"` 74 | } `json:"object_roles"` 75 | RelatedFieldCounts struct { 76 | Admins int `json:"admins"` 77 | Inventories int `json:"inventories"` 78 | JobTemplates int `json:"job_templates"` 79 | Projects int `json:"projects"` 80 | Teams int `json:"teams"` 81 | Users int `json:"users"` 82 | } `json:"related_field_counts"` 83 | } `json:"summary_fields"` 84 | Type string `json:"type"` 85 | URL string `json:"url"` 86 | } 87 | -------------------------------------------------------------------------------- /towerapi/params/params.go: -------------------------------------------------------------------------------- 1 | package params 2 | 3 | type ListParams struct { 4 | OrderBy string `url:"order_by,omitempty"` 5 | PageSize int `url:"page_size,omitempty"` 6 | Page int `url:"page,omitempty"` 7 | Search string `url:"search,omitempty"` 8 | Name string `url:"name,omitempty"` 9 | } 10 | -------------------------------------------------------------------------------- /towerapi/projects/projects.go: -------------------------------------------------------------------------------- 1 | package projects 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mpeter/go-towerapi/towerapi/errors" 7 | "github.com/mpeter/go-towerapi/towerapi/params" 8 | "github.com/mpeter/sling" 9 | ) 10 | 11 | const basePath = "projects/" 12 | 13 | // Service is an interface for interfacing with the 14 | // endpoints of the Ansible Tower API 15 | type Service struct { 16 | sling *sling.Sling 17 | } 18 | 19 | // NewService handles communication with auth project related methods of the 20 | // Ansible Tower API. 21 | func NewService(sling *sling.Sling) *Service { 22 | return &Service{ 23 | sling: sling.Path(basePath), 24 | } 25 | } 26 | 27 | // Create creates a new Project 28 | func (s *Service) Create(r *Request) (*Project, error) { 29 | project := new(Project) 30 | apierr := new(errors.APIError) 31 | _, err := s.sling.New().Post("").BodyJSON(r).Receive(project, apierr) 32 | return project, errors.BuildError(err, apierr) 33 | } 34 | 35 | // Updates modifies an existing project 36 | func (s *Service) Update(r *Request) (*Project, error) { 37 | project := new(Project) 38 | apierr := new(errors.APIError) 39 | _, err := s.sling.New().Put(r.ID+"/").BodyJSON(r).Receive(project, apierr) 40 | return project, errors.BuildError(err, apierr) 41 | } 42 | 43 | func (s *Service) Delete(id string) error { 44 | _, err := s.sling.New().Delete(id + "/").ReceiveSuccess(nil) 45 | return errors.BuildError(err, nil) 46 | } 47 | 48 | func (s *Service) List() ([]Project, error) { 49 | projects := new(Projects) 50 | apierr := new(errors.APIError) 51 | _, err := s.sling.New().Get("").Receive(projects, apierr) 52 | return projects.Results, errors.BuildError(err, apierr) 53 | } 54 | 55 | func (s *Service) ListByName(name string) ([]Project, error) { 56 | projects := new(Projects) 57 | apierr := new(errors.APIError) 58 | params := ¶ms.ListParams{Name: name} 59 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(projects, apierr) 60 | return projects.Results, errors.BuildError(err, apierr) 61 | } 62 | 63 | func (s *Service) GetByName(name string) (*Project, error) { 64 | projects := new(Projects) 65 | apierr := new(errors.APIError) 66 | 67 | params := ¶ms.ListParams{Name: name} 68 | _, err := s.sling.New().Get("").QueryStruct(params).Receive(projects, apierr) 69 | if err := errors.BuildError(err, apierr); err != nil { 70 | return nil, err 71 | } 72 | if projects.Count == 0 { 73 | return nil, nil 74 | } else if projects.Count > 1 { 75 | return nil, fmt.Errorf("Exact search returned more than 1 result for %s, should never happen", name) 76 | } 77 | results := projects.Results[0] 78 | return &results, nil 79 | } 80 | 81 | func (s *Service) GetByID(id string) (*Project, error) { 82 | project := new(Project) 83 | apierr := new(errors.APIError) 84 | _, err := s.sling.New().Get(id+"/").Receive(project, apierr) 85 | return project, errors.BuildError(err, apierr) 86 | } 87 | -------------------------------------------------------------------------------- /towerapi/projects/projects_struct.go: -------------------------------------------------------------------------------- 1 | package projects 2 | 3 | type Request struct { 4 | ID string `json:"-"` 5 | Name string `json:"name"` 6 | Description string `json:"description"` 7 | LocalPath string `json:"local_path"` 8 | ScmType string `json:"scm_type"` 9 | ScmURL string `json:"scm_url"` 10 | ScmBranch string `json:"scm_branch"` 11 | ScmClean bool `json:"scm_clean"` 12 | ScmDeleteOnUpdate bool `json:"scm_delete_on_update"` 13 | Credential *int `json:"credential" mapstructure:"credential_id"` 14 | Organization *int `json:"organization" mapstructure:"organization_id"` 15 | ScmUpdateOnLaunch bool `json:"scm_update_on_launch"` 16 | ScmUpdateCacheTimeout int `json:"scm_update_cache_timeout"` 17 | } 18 | 19 | type Projects struct { 20 | Count int `json:"count"` 21 | Next string `json:"next"` 22 | Previous string `json:"previous"` 23 | Results []Project `json:"results"` 24 | } 25 | 26 | type Project struct { 27 | Created string `json:"created"` 28 | Credential int `json:"credential"` 29 | Description string `json:"description"` 30 | HasSchedules bool `json:"has_schedules"` 31 | ID int `json:"id"` 32 | LastJobFailed bool `json:"last_job_failed"` 33 | LastJobRun string `json:"last_job_run"` 34 | LastUpdateFailed bool `json:"last_update_failed"` 35 | LastUpdated string `json:"last_updated"` 36 | LocalPath string `json:"local_path"` 37 | Modified string `json:"modified"` 38 | Name string `json:"name"` 39 | NextJobRun string `json:"next_job_run"` 40 | Organization int `json:"organization"` 41 | Related struct { 42 | AccessList string `json:"access_list"` 43 | ActivityStream string `json:"activity_stream"` 44 | CreatedBy string `json:"created_by"` 45 | Credential string `json:"credential"` 46 | LastJob string `json:"last_job"` 47 | LastUpdate string `json:"last_update"` 48 | NextSchedule string `json:"next_schedule"` 49 | NotificationTemplatesAny string `json:"notification_templates_any"` 50 | NotificationTemplatesError string `json:"notification_templates_error"` 51 | NotificationTemplatesSuccess string `json:"notification_templates_success"` 52 | ObjectRoles string `json:"object_roles"` 53 | Organization string `json:"organization"` 54 | Playbooks string `json:"playbooks"` 55 | ProjectUpdates string `json:"project_updates"` 56 | Schedules string `json:"schedules"` 57 | Teams string `json:"teams"` 58 | Update string `json:"update"` 59 | } `json:"related"` 60 | ScmBranch string `json:"scm_branch"` 61 | ScmClean bool `json:"scm_clean"` 62 | ScmDeleteOnNextUpdate bool `json:"scm_delete_on_next_update"` 63 | ScmDeleteOnUpdate bool `json:"scm_delete_on_update"` 64 | ScmType string `json:"scm_type"` 65 | ScmUpdateCacheTimeout int `json:"scm_update_cache_timeout"` 66 | ScmUpdateOnLaunch bool `json:"scm_update_on_launch"` 67 | ScmURL string `json:"scm_url"` 68 | Status string `json:"status"` 69 | SummaryFields struct { 70 | CreatedBy struct { 71 | FirstName string `json:"first_name"` 72 | ID int `json:"id"` 73 | LastName string `json:"last_name"` 74 | Username string `json:"username"` 75 | } `json:"created_by"` 76 | Credential struct { 77 | Cloud bool `json:"cloud"` 78 | Description string `json:"description"` 79 | ID int `json:"id"` 80 | Kind string `json:"kind"` 81 | Name string `json:"name"` 82 | } `json:"credential"` 83 | LastJob struct { 84 | Description string `json:"description"` 85 | Failed bool `json:"failed"` 86 | Finished string `json:"finished"` 87 | ID int `json:"id"` 88 | Name string `json:"name"` 89 | Status string `json:"status"` 90 | } `json:"last_job"` 91 | LastUpdate struct { 92 | Description string `json:"description"` 93 | Failed bool `json:"failed"` 94 | ID int `json:"id"` 95 | Name string `json:"name"` 96 | Status string `json:"status"` 97 | } `json:"last_update"` 98 | ObjectRoles struct { 99 | AdminRole struct { 100 | Description string `json:"description"` 101 | ID int `json:"id"` 102 | Name string `json:"name"` 103 | } `json:"admin_role"` 104 | ReadRole struct { 105 | Description string `json:"description"` 106 | ID int `json:"id"` 107 | Name string `json:"name"` 108 | } `json:"read_role"` 109 | UpdateRole struct { 110 | Description string `json:"description"` 111 | ID int `json:"id"` 112 | Name string `json:"name"` 113 | } `json:"update_role"` 114 | UseRole struct { 115 | Description string `json:"description"` 116 | ID int `json:"id"` 117 | Name string `json:"name"` 118 | } `json:"use_role"` 119 | } `json:"object_roles"` 120 | Organization struct { 121 | Description string `json:"description"` 122 | ID int `json:"id"` 123 | Name string `json:"name"` 124 | } `json:"organization"` 125 | } `json:"summary_fields"` 126 | Type string `json:"type"` 127 | URL string `json:"url"` 128 | } 129 | -------------------------------------------------------------------------------- /towerapi/towerapi.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | "os" 7 | 8 | "github.com/mpeter/go-towerapi/towerapi/authtoken" 9 | "github.com/mpeter/go-towerapi/towerapi/credentials" 10 | "github.com/mpeter/go-towerapi/towerapi/errors" 11 | "github.com/mpeter/go-towerapi/towerapi/groups" 12 | "github.com/mpeter/go-towerapi/towerapi/hosts" 13 | "github.com/mpeter/go-towerapi/towerapi/inventories" 14 | "github.com/mpeter/go-towerapi/towerapi/job_templates" 15 | "github.com/mpeter/go-towerapi/towerapi/organizations" 16 | "github.com/mpeter/go-towerapi/towerapi/projects" 17 | "github.com/mpeter/sling" 18 | ) 19 | 20 | const ( 21 | libraryVersion = "0.1.0" 22 | userAgent = "go-towerapi/" + libraryVersion 23 | mediaType = "application/json" 24 | defaultEndpoint = "http://localhost/api/v1/" 25 | defaultUsername = "admin" 26 | defaultPassword = "admin" 27 | ) 28 | 29 | // Client manages communication with Ansible Tower V1 API. 30 | type Client struct { 31 | // HTTP client used to communicate with the Ansible Tower API. 32 | sling *sling.Sling 33 | 34 | // AuthToken obtained from calling Ansible Tower API /authtoken/ endpoint 35 | Token *authtoken.AuthToken 36 | 37 | // User agent for client 38 | UserAgent string 39 | 40 | // Services used for communicating with the API 41 | AuthToken *authtoken.Service 42 | Credentials *credentials.Service 43 | Groups *groups.Service 44 | Hosts *hosts.Service 45 | Inventories *inventories.Service 46 | JobTemplates *job_templates.Service 47 | Organizations *organizations.Service 48 | Projects *projects.Service 49 | 50 | //ActivityStream *ActivityStreamService 51 | //AdHocCommands *AdHocCommandsService 52 | //Config *ConfigService 53 | //Dashboard *DashboardService 54 | //InventoryScripts *InventoryScriptsService 55 | //InventorySources *InventorySourcesService 56 | //JobEvents *JobEventsService 57 | //Jobs *JobsService 58 | //Labels *LabelsService 59 | //Me *MeService 60 | //NotificationTemplates *NotificationTemplatesService 61 | //Notifications *NotificationsService 62 | //Ping *PingService 63 | //Projects *ProjectsService 64 | //Roles *RolesService 65 | //Schedules *SchedulesService 66 | //SystemJobTemplates *SystemJobTemplatesService 67 | //SystemJobs *SystemJobsService 68 | //Teams *TeamsService 69 | //UnifiedJobTemplates *UnifiedJobTemplatesService 70 | //UnifiedJobs *UnifiedJobsService 71 | //Users *UsersService 72 | 73 | } 74 | 75 | type Config struct { 76 | Endpoint string 77 | Username string 78 | Password string 79 | AuthToken *authtoken.AuthToken 80 | HttpClient *http.Client 81 | } 82 | 83 | func DefaultConfig() *Config { 84 | 85 | config := &Config{ 86 | Endpoint: "http://127.0.0.1/api/v1/", 87 | Username: "admin", 88 | Password: "", 89 | AuthToken: nil, 90 | HttpClient: http.DefaultClient, 91 | } 92 | 93 | if e := os.Getenv("TOWER_ENDOINT"); e != "" { 94 | config.Endpoint = e 95 | } 96 | if u := os.Getenv("TOWER_USERNAME"); u != "" { 97 | config.Username = u 98 | } 99 | if p := os.Getenv("TOWER_PASSWORD"); p != "" { 100 | config.Password = p 101 | } 102 | 103 | return config 104 | } 105 | 106 | func (c *Config) LoadAndValidate() error { 107 | 108 | base := sling.New().Client(c.HttpClient).Base(c.Endpoint) 109 | body := &authtoken.CreateRequest{ 110 | Username: c.Username, 111 | Password: c.Password, 112 | } 113 | token := new(authtoken.AuthToken) 114 | apierr := new(errors.APIError) 115 | _, err := base.Post("authtoken/").BodyJSON(body).Receive(token, apierr) 116 | if error := errors.BuildError(err, apierr); error != nil { 117 | return error 118 | } 119 | c.AuthToken = token 120 | return nil 121 | } 122 | 123 | func NewClient(c *Config) (*Client, error) { 124 | 125 | if c.HttpClient == nil { 126 | c.HttpClient = http.DefaultClient 127 | } 128 | 129 | base := sling.New().Client(c.HttpClient).Base(c.Endpoint) 130 | base.Set("Authorization", "Token "+c.AuthToken.Token) 131 | 132 | return &Client{ 133 | sling: base, 134 | 135 | AuthToken: authtoken.NewService(base.New()), 136 | Credentials: credentials.NewService(base.New()), 137 | Groups: groups.NewService(base.New()), 138 | Hosts: hosts.NewService(base.New()), 139 | Inventories: inventories.NewService(base.New()), 140 | JobTemplates: job_templates.NewService(base.New()), 141 | Organizations: organizations.NewService(base.New()), 142 | Projects: projects.NewService(base.New()), 143 | 144 | //ActivityStream: NewActivityStreamService(base), 145 | //AdHocCommands: NewAdHocCommandsService(base), 146 | //Config: NewConfigService(base), 147 | //Dashboard: NewDashboardService(base), 148 | //InventoryScripts: NewInventoryScriptsService(base), 149 | //InventorySources: NewInventorySourcesService(base), 150 | //JobEvents: NewJobEventsService(base), 151 | //Jobs: NewJobsService(base), 152 | //Labels: NewLabelsService(base), 153 | //Me: NewMeService(base), 154 | //NotificationTemplates: NewNotificationTemplatesService(base), 155 | //Notifications: NewNotificationsService(base), 156 | //Ping: NewPingService(base), 157 | //Roles: NewRolesService(base), 158 | //Schedules: NewSchedulesService(base), 159 | //SystemJobTemplates: NewSystemJobTemplatesService(base), 160 | //SystemJobs: NewSystemJobsService(base), 161 | //Teams: NewTeamsService(base), 162 | //UnifiedJobTemplates: NewUnifiedJobTemplatesService(base), 163 | //UnifiedJobs: NewUnifiedJobsService(base), 164 | //Users: NewUsersService(base), 165 | }, nil 166 | } 167 | -------------------------------------------------------------------------------- /towerapi/towerapi_test.go: -------------------------------------------------------------------------------- 1 | package towerapi 2 | 3 | /* 4 | import ( 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/http/httptest" 9 | "net/http/httputil" 10 | "net/url" 11 | "os" 12 | "reflect" 13 | "strings" 14 | "testing" 15 | ) 16 | 17 | var ( 18 | mux *http.ServeMux 19 | 20 | client *Client 21 | 22 | server *httptest.Server 23 | ) 24 | 25 | func setup() { 26 | mux = http.NewServeMux() 27 | server = httptest.NewServer(mux) 28 | os.Setenv("TOWER_ENDPOINT", defaultEndpoint) 29 | os.Setenv("TOWER_USERNAME", defaultUsername) 30 | os.Setenv("TOWER_PASSWORD", defaultPassword) 31 | client, _ = NewDefaultClient(nil) 32 | url, _ := url.Parse(server.URL) 33 | client.Endpoint = url 34 | } 35 | 36 | func teardown() { 37 | server.Close() 38 | } 39 | 40 | func testMethod(t *testing.T, r *http.Request, expected string) { 41 | if expected != r.Method { 42 | t.Errorf("Request method = %v, expected %v", r.Method, expected) 43 | } 44 | } 45 | 46 | type values map[string]string 47 | 48 | func testURLParseError(t *testing.T, err error) { 49 | if err == nil { 50 | t.Errorf("Expected error to be returned") 51 | } 52 | if err, ok := err.(*url.Error); !ok || err.Op != "parse" { 53 | t.Errorf("Expected URL parse error, got %+v", err) 54 | } 55 | } 56 | 57 | func testClientDefaultEndpoint(t *testing.T, c *Client) { 58 | if c.Endpoint == nil || c.Endpoint.String() != defaultEndpoint { 59 | t.Errorf("NewClient Endpoint = %v, expected %v", c.Endpoint, defaultEndpoint) 60 | } 61 | } 62 | 63 | func testClientDefaultUserAgent(t *testing.T, c *Client) { 64 | if c.UserAgent != userAgent { 65 | t.Errorf("NewClick UserAgent = %v, expected %v", c.UserAgent, userAgent) 66 | } 67 | } 68 | 69 | func testClientDefaults(t *testing.T, c *Client) { 70 | testClientDefaultEndpoint(t, c) 71 | testClientDefaultUserAgent(t, c) 72 | } 73 | 74 | func TestNewClient(t *testing.T) { 75 | c, _ := NewDefaultClient(nil) 76 | testClientDefaults(t, c) 77 | } 78 | 79 | func TestNew(t *testing.T) { 80 | c, err := New(nil) 81 | 82 | if err != nil { 83 | t.Fatalf("New(): %v", err) 84 | } 85 | testClientDefaults(t, c) 86 | } 87 | 88 | func TestNewRequest(t *testing.T) { 89 | c, _ := NewDefaultClient(nil) 90 | 91 | inURL, outURL := "ping/", defaultEndpoint+"ping/" 92 | req, _ := c.NewRequest("GET", inURL, nil) 93 | 94 | // test relative URL was expanded 95 | if req.URL.String() != outURL { 96 | t.Errorf("NewRequest(%v) URL = %v, expected %v", inURL, req.URL, outURL) 97 | } 98 | 99 | // test default user-agent is attached to the request 100 | userAgent := req.Header.Get("User-Agent") 101 | if c.UserAgent != userAgent { 102 | t.Errorf("NewRequest() User-Agent = %v, expected %v", userAgent, c.UserAgent) 103 | } 104 | } 105 | 106 | func TestNewRequest_badURL(t *testing.T) { 107 | c, _ := NewDefaultClient(nil) 108 | _, err := c.NewRequest("GET", ":", nil) 109 | testURLParseError(t, err) 110 | } 111 | 112 | func TestNewRequest_withCustomUserAgent(t *testing.T) { 113 | ua := "testing" 114 | c, err := New(nil, SetUserAgent(ua)) 115 | 116 | if err != nil { 117 | t.Fatalf("New() unexpected error: %v", err) 118 | } 119 | 120 | req, _ := c.NewRequest("GET", "/foo", nil) 121 | 122 | expected := fmt.Sprintf("%s+%s", ua, userAgent) 123 | if got := req.Header.Get("User-Agent"); got != expected { 124 | t.Errorf("New() UserAgent = %s; expected %s", got, expected) 125 | } 126 | } 127 | 128 | func TestDo(t *testing.T) { 129 | setup() 130 | defer teardown() 131 | 132 | type foo struct { 133 | A string 134 | } 135 | 136 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 137 | if m := "GET"; m != r.Method { 138 | t.Errorf("Request method = %v, expected %v", r.Method, m) 139 | } 140 | fmt.Fprint(w, `{"A":"a"}`) 141 | }) 142 | 143 | req, _ := client.NewRequest("GET", "/", nil) 144 | body := new(foo) 145 | _, err := client.Do(req, body) 146 | if err != nil { 147 | t.Fatalf("Do(): %v", err) 148 | } 149 | 150 | expected := &foo{"a"} 151 | if !reflect.DeepEqual(body, expected) { 152 | t.Errorf("Response body = %v, expected %v", body, expected) 153 | } 154 | } 155 | 156 | func TestDo_httpError(t *testing.T) { 157 | setup() 158 | defer teardown() 159 | 160 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 161 | http.Error(w, "Bad Request", 400) 162 | }) 163 | 164 | req, _ := client.NewRequest("GET", "/", nil) 165 | _, err := client.Do(req, nil) 166 | 167 | if err == nil { 168 | t.Error("Expected HTTP 400 error.") 169 | } 170 | } 171 | 172 | // Test handling of an error caused by the internal http client's Do() 173 | // function. 174 | func TestDo_redirectLoop(t *testing.T) { 175 | setup() 176 | defer teardown() 177 | 178 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 179 | http.Redirect(w, r, "/", http.StatusFound) 180 | }) 181 | 182 | req, _ := client.NewRequest("GET", "/", nil) 183 | _, err := client.Do(req, nil) 184 | 185 | if err == nil { 186 | t.Error("Expected error to be returned.") 187 | } 188 | if err, ok := err.(*url.Error); !ok { 189 | t.Errorf("Expected a URL error; got %#v.", err) 190 | } 191 | } 192 | 193 | func TestCheckResponse(t *testing.T) { 194 | res := &http.Response{ 195 | Request: &http.Request{}, 196 | StatusCode: http.StatusBadRequest, 197 | Body: ioutil.NopCloser(strings.NewReader(`{"message":"m", 198 | "errors": [{"resource": "r", "field": "f", "code": "c"}]}`)), 199 | } 200 | err := CheckResponse(res).(*ErrorResponse) 201 | 202 | if err == nil { 203 | t.Fatalf("Expected error response.") 204 | } 205 | 206 | expected := &ErrorResponse{ 207 | Response: res, 208 | Message: "m", 209 | } 210 | if !reflect.DeepEqual(err, expected) { 211 | t.Errorf("Error = %#v, expected %#v", err, expected) 212 | } 213 | } 214 | 215 | // ensure that we properly handle API errors that do not contain a response 216 | // body 217 | func TestCheckResponse_noBody(t *testing.T) { 218 | res := &http.Response{ 219 | Request: &http.Request{}, 220 | StatusCode: http.StatusBadRequest, 221 | Body: ioutil.NopCloser(strings.NewReader("")), 222 | } 223 | err := CheckResponse(res).(*ErrorResponse) 224 | 225 | if err == nil { 226 | t.Errorf("Expected error response.") 227 | } 228 | 229 | expected := &ErrorResponse{ 230 | Response: res, 231 | } 232 | if !reflect.DeepEqual(err, expected) { 233 | t.Errorf("Error = %#v, expected %#v", err, expected) 234 | } 235 | } 236 | 237 | func TestErrorResponse_Error(t *testing.T) { 238 | res := &http.Response{Request: &http.Request{}} 239 | err := ErrorResponse{Message: "m", Response: res} 240 | if err.Error() == "" { 241 | t.Errorf("Expected non-empty ErrorResponse.Error()") 242 | } 243 | } 244 | 245 | func TestDo_completion_callback(t *testing.T) { 246 | setup() 247 | defer teardown() 248 | 249 | type foo struct { 250 | A string 251 | } 252 | 253 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 254 | if m := "GET"; m != r.Method { 255 | t.Errorf("Request method = %v, expected %v", r.Method, m) 256 | } 257 | fmt.Fprint(w, `{"A":"a"}`) 258 | }) 259 | 260 | req, _ := client.NewRequest("GET", "/", nil) 261 | body := new(foo) 262 | var completedReq *http.Request 263 | var completedResp string 264 | client.OnRequestCompleted(func(req *http.Request, resp *http.Response) { 265 | completedReq = req 266 | b, err := httputil.DumpResponse(resp, true) 267 | if err != nil { 268 | t.Errorf("Failed to dump response: %s", err) 269 | } 270 | completedResp = string(b) 271 | }) 272 | _, err := client.Do(req, body) 273 | if err != nil { 274 | t.Fatalf("Do(): %v", err) 275 | } 276 | if !reflect.DeepEqual(req, completedReq) { 277 | t.Errorf("Completed request = %v, expected %v", completedReq, req) 278 | } 279 | expected := `{"A":"a"}` 280 | if !strings.Contains(completedResp, expected) { 281 | t.Errorf("expected response to contain %v, Response = %v", expected, completedResp) 282 | } 283 | } 284 | 285 | func TestAddOptions(t *testing.T) { 286 | cases := []struct { 287 | name string 288 | path string 289 | expected string 290 | opts *ListOptions 291 | isErr bool 292 | }{ 293 | { 294 | name: "add options", 295 | path: "/action", 296 | expected: "/action?page=1", 297 | opts: &ListOptions{Page: 1}, 298 | isErr: false, 299 | }, 300 | { 301 | name: "add options with existing parameters", 302 | path: "/action?scope=all", 303 | expected: "/action?page=1&scope=all", 304 | opts: &ListOptions{Page: 1}, 305 | isErr: false, 306 | }, 307 | } 308 | 309 | for _, c := range cases { 310 | got, err := addOptions(c.path, c.opts) 311 | if c.isErr && err == nil { 312 | t.Errorf("%q expected error but none was encountered", c.name) 313 | continue 314 | } 315 | 316 | if !c.isErr && err != nil { 317 | t.Errorf("%q unexpected error: %v", c.name, err) 318 | continue 319 | } 320 | 321 | gotURL, err := url.Parse(got) 322 | if err != nil { 323 | t.Errorf("%q unable to parse returned URL", c.name) 324 | continue 325 | } 326 | 327 | expectedURL, err := url.Parse(c.expected) 328 | if err != nil { 329 | t.Errorf("%q unable to parse expected URL", c.name) 330 | continue 331 | } 332 | 333 | if g, e := gotURL.Path, expectedURL.Path; g != e { 334 | t.Errorf("%q path = %q; expected %q", c.name, g, e) 335 | continue 336 | } 337 | 338 | if g, e := gotURL.Query(), expectedURL.Query(); !reflect.DeepEqual(g, e) { 339 | t.Errorf("%q query = %#v; expected %#v", c.name, g, e) 340 | continue 341 | } 342 | } 343 | } 344 | 345 | func TestCustomUserAgent(t *testing.T) { 346 | c, err := New(nil, SetUserAgent("testing")) 347 | 348 | if err != nil { 349 | t.Fatalf("New() unexpected error: %v", err) 350 | } 351 | 352 | expected := fmt.Sprintf("%s+%s", "testing", userAgent) 353 | if got := c.UserAgent; got != expected { 354 | t.Errorf("New() UserAgent = %s; expected %s", got, expected) 355 | } 356 | } 357 | */ 358 | --------------------------------------------------------------------------------