# -*- tcl -*- # Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'dev make' or bin/punkmake to update from -buildversion.txt # module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.3.tm # # Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. # Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository. # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # (C) 2025 # # @@ Meta Begin # Application punk::netbox 999999.0a1.0 # Meta platform tcl # Meta license MIT # @@ Meta End # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # doctools header # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ #*** !doctools #[manpage_begin shellspy_module_punk::netbox 0 999999.0a1.0] #[copyright "2025"] #[titledesc {Module API}] [comment {-- Name section and table of contents description --}] #[moddesc {-}] [comment {-- Description at end of page heading --}] #[require punk::netbox] #[keywords module] #[description] #[para] - # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ #*** !doctools #[section Overview] #[para] overview of punk::netbox #[subsection Concepts] #[para] - # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Requirements # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ #*** !doctools #[subsection dependencies] #[para] packages used by punk::netbox #[list_begin itemized] package require Tcl 8.6- package require http package require rest package require punk::args #*** !doctools #[item] [package {Tcl 8.6}] #[item] [package {http}] # #package require frobz # #*** !doctools # #[item] [package {frobz}] #*** !doctools #[list_end] # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ #*** !doctools #[section API] # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # oo::class namespace # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ #tcl::namespace::eval punk::netbox::class { #*** !doctools #[subsection {Namespace punk::netbox::class}] #[para] class definitions #if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} { #*** !doctools #[list_begin enumerated] # oo::class create interface_sample1 { # #*** !doctools # #[enum] CLASS [class interface_sample1] # #[list_begin definitions] # method test {arg1} { # #*** !doctools # #[call class::interface_sample1 [method test] [arg arg1]] # #[para] test method # puts "test: $arg1" # } # #*** !doctools # #[list_end] [comment {-- end definitions interface_sample1}] # } #*** !doctools #[list_end] [comment {--- end class enumeration ---}] #} #} # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ tcl::namespace::eval punk::netbox {} # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ #*** !doctools #[section Internal] tcl::namespace::eval punk::netbox::system { #*** !doctools #[subsection {Namespace punk::netbox::system}] #[para] Internal functions that are not part of the API tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase punk::args::define { @id -id ::punk::netbox::system::make_rest_func @leaders -min 2 -max 2 commandname -help\ "Fully qualified commandname. There must be an existing punk::args definition with @id directive -id matching the name" endpoint -help\ "The subpath to be appended to the base url. e.g api/ipam/ip-addresses/ api/ipam/ip-addresses/{id}/" -verb -default get -choices {get post patch head put delete} -body -default optional -choicecolumns 2 -choices {none optional required mime_multipart}\ -choicelabels { none\ " The call has no request body, none must be supplied." optional\ " A request body can be supplied, but is not required" required\ " A request body must be supplied." mime_multipart\ " A request body must be supplied and will be interpreted as each argument representing one part of a mime/multipart document. Arguments must be lists containing 2 elements, a list of header keys and values, and the mime part body, in this order." } } #A somewhat sanitized config for outputting to stderr etc #Obscure at least full Authorization Token #todo - other headers? proc obscured_config {cfg} { set sanconfig $cfg if {[dict exists $cfg headers]} { set hdrs [dict get $cfg headers] if {[dict exists $hdrs Authorization]} { set auth [dict get $hdrs Authorization] if {[dict exists $auth Token]} { dict set auth Token "[string range [dict get $auth Token] 0 5]..." dict set hdrs Authorization $auth dict set sanconfig headers $hdrs } } } return $sanconfig } proc make_rest_func {args} { set argd [punk::args::parse $args withid ::punk::netbox::system::make_rest_func] lassign [dict values $argd] leaders opts values received set commandname [dict get $leaders commandname] set endpoint [dict get $leaders endpoint] set verb [dict get $opts -verb] set body [dict get $opts -body] set custom [dict create\ %commandname% $commandname\ %endpoint% $endpoint\ %verb% $verb\ %body% $body\ %showpagedict% {!@@results @@results/@*/@*.@*}\ %showpagedict2% {@@results/@*/@*.@* !@@results}\ %showdict% {*}\ %showdict2% {*/*}\ %showlistofdicts% {@*/@*.@*}\ ] if {$commandname eq "::punk::netbox::status"} { #we get duplicate django-version for %showdict% - todo - something. dict set custom %showdict% {@@django-version @@installed-apps/@*.@* !@@installed-apps} dict set custom %showdict2% {@@installed-apps/@*.@* !@@installed-apps} } set procbody [string map $custom { set argd [punk::args::parse $args withid %commandname%] lassign [dict values $argd] leaders opts values received solos multis set apicontextid [dict get $leaders apicontextid] if {[dict exists $received -RETURN]} { set returntype [dict get $opts -RETURN] } else { if {[dict exists $opts -RETURN]} { #not received - but has default set returntype [dict get $opts -RETURN] } else { #fallback if -RETURN was defined without a default or was omitted set returntype dict } } set FORCE 1 if {[dict exists $opts -FORCE]} { set FORCE [dict get $opts -FORCE] } set query [list] ;#use list not dict - allows repeated params dict for {k val} $opts { switch -- $k { -CUSTOM_PARAM { #'-multiple true' foreach kv $val { lassign $kv paramname value lappend query $paramname $value } } -RETURN { #ignore - already handled } default { if {[string match *_FILTER $k]} { #all _FILTER methods are '-multiple true' - so are present in $opts as a single key with a value that is a list #e.g -X_Y_FILTER "blah" set parts [split $k _] set name1 [string range [string tolower [lindex $parts 0]] 1 end] ;#strip leading dash off first part set nametail [string tolower [lrange $parts 1 end-1]] set paramname [join [list $name1 {*}$nametail] _] foreach fv $val { lassign $fv filter value ;#filter is n,gte,lte etc lappend query ${paramname}__$filter $value } } else { set paramname [string range $k 1 end] if {$paramname in $multis} { foreach v $val { lappend query $paramname $v } } else { lappend query $paramname $val } } } } } set body %body% switch -- $body { required { set requestbody [dict get $values body] } optional { if {[dict exists $received body]} { set requestbody [dict get $values body] } else { set requestbody "" } } } upvar ::punk::netbox::contexts contexts if {![dict exists $contexts $apicontextid]} { error "specified contextid '$apicontextid' not found" } set config [dict create\ format json\ result json\ ] #rest api documentation is unclear on 'result' field #note our default: result json #this actually converts the json to a dict dict set config headers [list Authorization [list Token [dict get $contexts $apicontextid token value]]] if {$returntype in "json jsondump"} { #if we set result json - we get a dict instead of json :/ dict set config result raw } if {$body in {required optional}} { #content type for the request data dict set config headers content-type "application/json" } #variable headerdict #set config [dict create\ # headers $headerdict\ #] set url [dict get $contexts $apicontextid url value] set endpoint "%endpoint%" if {[string first {{id}} $endpoint] != -1} { set id [dict get $values id] set endpoint [string map [list {{id}} $id] $endpoint] } #todo - only show if debug (and obscure Authorization Token) set sanconfig [punk::netbox::system::obscured_config $config] puts stderr "url:${url}$endpoint query:'$query' verb:%verb% config:'$sanconfig'" if {$FORCE} { #FORCE is true for most operations (and no -FORCE option even available) but the option exists and defaults to false for specifically unsafe #e.g delete operations on entire endpoints if {$body in {required optional}} { set result [::rest::%verb% ${url}$endpoint $query $config $requestbody] } else { set result [::rest::%verb% ${url}$endpoint $query $config] } } else { puts stderr "%commandname% not called because -FORCE is false" set sanconfig [punk::netbox::system::obscured_config $config] puts "url:${url}$endpoint query:'$query' verb:%verb% config:'$sanconfig'" return } switch -exact -- $returntype { showpagedict { #return [punk::lib::showdict $result !@@results @@results/@*/@*.@*] return [punk::lib::showdict $result %showpagedict%] } showpagedict2 { #return [punk::lib::showdict $result @@results/@*/@*.@* !@@results] return [punk::lib::showdict $result %showpagedict2%] } showdict { return [punk::lib::showdict $result %showdict%] } showdict2 { return [punk::lib::showdict $result %showdict2%] } showlist { return [punk::lib::showdict -roottype list $result] } showlistofdicts { return [punk::lib::showdict $result %showlistofdicts%] } jsondump { package require huddle::json #pretty-print via huddle (inefficient review) set h [huddle::json::json2huddle parse $result] return [huddle::jsondump $h] } linelist { set ret "" foreach r $result { append ret $r \n } return $ret } default { #plain result: (list or dict) or json - the counterintuitive 'result' field set to raw above sets the rest resulting format to json return $result } } }] proc $commandname {args} $procbody } } tcl::namespace::eval punk::netbox { # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # Base namespace # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ #*** !doctools #[subsection {Namespace punk::netbox}] #[para] Core API functions for punk::netbox #[list_begin definitions] variable PUNKARGS variable has_tls set has_tls [expr {![catch {package require tls}]}] if {$has_tls} { ::http::register https 443 ::tls::socket } variable ipam #TEMP - todo variable headerdict set headerdict [dict create\ Authorization "Token af65b993000874eaefeca0fa02b0d86014e48365"\ ] #temp variable url https://www.netbox1.intx.com.au/ variable contexts [dict create] variable context_id 0 proc api_context_names {} { variable contexts return [dict keys $contexts] } lappend PUNKARGS [list { @id -id ::punk::netbox::api_contexts @cmd -name punk::netbox::api_contexts -help\ "Show in-memory api contexts. These are named contexts for calling the NETBOX rest api. They are loaded using api_contexts_load from a .toml configuration file, or created using api_context_create." -return -default table -choices {table tableobject dict} -fields -type list -default {url tokentail comment} -choices {url token tokentail comment *} -choicemultiple {0 -1} -choicerestricted 0 -help\ "The * token can be included in the list of specified fields, and represents any other available fields found from the matched contexts" @values -min 0 -max 1 globname -default * -help\ "pattern to match the context name(s)" }] proc api_contexts {args} { set argd [punk::args::parse $args withid ::punk::netbox::api_contexts] lassign [dict values $argd] leaders opts values received set returntype [dict get $opts -return] set fields [dict get $opts -fields] set globname [dict get $values globname] variable contexts set matches [dict keys $contexts $globname] if {"*" in $fields} { set starposn [lsearch -exact $fields *] set before [lrange $fields 0 $starposn-1] set after [lrange $fields $starposn+1 end] set allspecified [list {*}$before {*}$after] # use * as placeholder for all others not specified - retain order of specified columns set fields [list] #check fields in all matches set starfields [list] if {"tokentail" ni $allspecified} { #calculated column lappend starfields tokentail } foreach k $matches { set contextinfo [dict get $contexts $k] dict for {valkey valinfo} $contextinfo { if {$valkey ni $allspecified && $valkey ni $starfields} { lappend starfields $valkey } } } set fields [list {*}$before {*}$starfields {*}$after] } switch -- $returntype { table - tableobject { package require textblock set t [textblock::table -return tableobject -minwidth 75 -headers [list contextid {*}$fields]] foreach k $matches { set contextinfo [dict get $contexts $k] set tokentail "" if {"tokentail" in $fields} { #computed column if {[dict exists $contextinfo token]} { set tokentail [string range [dict get $contextinfo token value] end-5 end] } } set rowdata [list $k] foreach f $fields { if {[dict exists $contextinfo $f value]} { lappend rowdata [dict get $contextinfo $f value] } else { if {$f eq "tokentail"} { lappend rowdata $tokentail } else { lappend rowdata "" } } } $t add_row $rowdata } if {$returntype eq "table"} { set tableview [$t print] $t destroy return $tableview } else { return $t } } dict { set result [dict create] foreach k $matches { set contextinfo [dict get $contexts $k] set tokentail "" if {"tokentail" in $fields} { #computed column if {[dict exists $contextinfo token]} { set tokentail [string range [dict get $contextinfo token value] end-5 end] } } dict set result $k {} ;#ensure record is output even if empty fieldlist foreach f $fields { if {[dict exists $contextinfo $f value]} { dict set result $k $f [dict get $contextinfo $f value] } else { if {$f eq "tokentail"} { dict set result $k tokentail $tokentail } } } #dict for {valkey valinfo} $contextinfo { # dict set result $k $valkey [dict get $valinfo value] #} } return $result } } } #get api handle(s) for a netbox server (with url and token) to pass to the punk::netbox api functions lappend PUNKARGS [list { @id -id ::punk::netbox::api_context_load @cmd -name punk::netbox::api_context_load -help\ "Load API context information (url token) from a .toml file in the data directory or from a specified file. To create an initial file, use api_context to create one or more named configurations specifying the url and authentication token. Then use api_context_save to persist them." @opts -contextname -default * -help\ "Name of an API context or a pattern for which contexts to load from the file." @values filepath -default "" -type file }] proc api_context_load {args} { set argd [punk::args::parse $args withid ::punk::netbox::api_context_load] lassign [dict values $argd] leaders opts values received set contextglob [dict get $opts -contextname] set filepath [dict get $values filepath] if {$filepath eq ""} { set filepath [_datafile] } if {![file exists $filepath]} { error "No existing datafile at '$filepath'\nUse api_context_create to configure a context and save it with api_context_save" } package require tomlish set tomldata [readFile $filepath] set tomlish [tomlish::from_toml $tomldata] ;#intermediate (unvalidated) representation of toml data - maintaining whitespace and comments set tomldict [tomlish::to_dict $tomlish] ;#lossy conversion to a programmatic structure (loss is of comments, whitespace) variable contexts #merge into any existing-in-memory loaded/created contexts set loaded [list] dict for {contextid contextinfo} $tomldict { if {[string match $contextglob $contextid]} { if {![dict exists $contextinfo url]} { puts "api_context_load warning: Loaded context $contextid is missing 'url' key" } if {![dict exists $contextinfo token]} { puts "api_context_load warning: Loaded context $contextid is missing 'token' key" } dict set contexts $contextid $contextinfo lappend loaded $contextid } } return $loaded } lappend PUNKARGS [list { @id -id ::punk::netbox::api_context_create @cmd -name punk::netbox::api_context_create -help\ "Create an in-memory configuration for an API context. This consists of a name (contextid) under which a url and authentication token are stored. It can optionally be persisted using api_context_save to the file of your choice, or to a reasonable default location. (see _datafile). The api_context_load function can be used to retrieve previously stored contextids instead of calling this function each time. A contextid is required when calling the netbox rest api functions such as ipam::vrfs This allows easy intermixing of calls to either the same or different servers using the different permissions granted by each token. " @leaders -min 1 -max 1 contextid -type string -help\ "Name for the api context. If saved to a .toml file, this will be the name of a toplevel table containing configuration elements such as url and token." @opts -property_value -type list -minsize 2 -maxsize 2 -multiple 1 -help\ "custom property and value. e.g property_value {comment {test comment}}" @values -min 2 -max 2 url -type string -help\ "Base url of netbox server" token -type string -help\ "Netbox API authentication token" }] proc api_context_create {args} { set argd [punk::args::parse $args withid ::punk::netbox::api_context_create] lassign [dict values $argd] leaders opts values received set contextid [dict get $leaders contextid] if {[dict exists $received -property_value]} { set propvals [dict get $opts -property_value] ;#multiple - as pairs } else { set propvals [list] } set baseurl [dict get $values url] set token [dict get $values token] variable contexts if {[dict exists $contexts $contextid]} { error "api_context_create a context with id '$contextid' already exists." } set allprops [dict create url [dict create type STRING value $baseurl] token [dict create type STRING value $token]] foreach pv $propvals { lassign $pv p v if {$p in {url token}} { puts stderr "ignoring -property_value $p - invalid - already specified in arguments" } #todo - multiline? dict set allprops $p [dict create type STRING value $v] } dict set contexts $contextid $allprops return $contextid } proc _homedir {} { if {[info exists ::env(HOME)]} { set home [file normalize $::env(HOME)] } else { #not available on 8.6? ok will error out here. set home [file tildeexpand ~] } return $home } lappend PUNKARGS [list { @id -id ::punk::netbox::_datafile @cmd -name punk::netbox::_datafile -help\ "Get the path for the default storage file used when an explicit path is not given by the caller to the api_context load/save functions. This file is in toml format. On any platform the XDG_DATA_HOME env var can be used to override the location, but on Windows the LOCALAPPDATA env var will specifiy the location if XDG_DATA_HOME is not set. Interfacing with a proper secret store should be considered as an alternative. On non Windows platforms: The XDG_DATA_HOME env var is the preferred choice of location - considered slightly more secure than XDG_CONFIG_HOME. A folder under the user's home directory, at .local/share/punk/netbox is chosen if XDG_DATA_HOME is not configured. " @leaders -min 0 -max 0 @opts -quiet -type none -help\ "Suppress warning given when the folder does not yet exist" @values -min 0 -max 0 }] proc _datafile {args} { set argd [punk::args::parse $args withid ::punk::netbox::_datafile] lassign [dict values $argd] leaders opts values received set be_quiet [dict exists $received -quiet] set was_noisy 0 if {[info exists ::env(XDG_DATA_HOME)]} { set data_home $::env(XDG_DATA_HOME) } else { if {$::tcl_platform(platform) eq "windows"} { set data_home $::env(LOCALAPPDATA) } else { set data_home [file join [_homedir] .local share] if {!$be_quiet} { puts stderr "Environment variable XDG_DATA_HOME does not exist - consider setting it if $data_home is not a suitable location" set was_noisy 1 } } } if {!$be_quiet && ![file exists $data_home]} { #parent folder for 'punk' config dir doesn't exist set msg "configuration location XDG_DATA_HOME or ~/.local/share (or LOCALAPPDATA on windows) at path '$data_home' does not yet exist" append msg \n " - please create it and/or set the appropriate env var." puts stderr $msg set was_noisy 1 } set punk_netbox_data_dir [file join $data_home punk netbox] if {!$be_quiet && ![file exists $punk_netbox_data_dir]} { set msg "punk::netbox data storage folder at $punk_netbox_data_dir does not yet exist." append msg \n " It will be created if api_context_save is called without specifying an alternate location." puts stderr $msg set was_noisy 1 } if {!$be_quiet && $was_noisy} { puts stderr "punk::netbox::_datafile - call with -quiet option to suppress these messages" } return [file join $punk_netbox_data_dir netbox_api_contexts.toml] } lappend PUNKARGS [list { @id -id ::punk::netbox::api_context_save @cmd -name punk::netbox::api_context_save -help\ "" @values contextid -type string -help\ "Name for the api context. If saved to a .toml file, this will be the name of a toplevel table containing configuration elements such as url and token." filepath -default "" -optional 1 -type file -help\ "Path of .toml configuration file containing API url and token information. If empty it will store under XDG_DATA_DIR if the env var is defined, or in the corresponding location within ~/.local/share. In both cases the subfolder netbox/punk will be used. These locations are fairly reasonable for sensitive data - but as tokens are not encrypted, a proper security store should be used instead if your risk-policy requires more serious security. " }] proc api_context_save {args} { set argd [punk::args::parse $args withid ::punk::netbox::api_context_save] lassign [dict values $argd] leaders opts values received set contextid [dict get $values contextid] set filepath [dict get $values filepath] variable contexts if {![dict exists $contexts $contextid]} { error "punk::netbox::api_context_save error. No context with id '$contextid' exists. Load from file, or create it using punk::netbox::api_context" } if {$filepath eq ""} { set filepath [_datafile -quiet] set filefolder [file dirname $filepath] if {![file exists $filefolder]} { file mkdir $filefolder } } set configdir [file dirname $filepath] if {![file exists $configdir]} { error "api_context_save error: folder $configdir doesn't exist" } package require tomlish if {[file exists $filepath]} { set existing_toml [readFile $filepath] set tomlish [tomlish::from_toml $existing_toml] set data_dict [tomlish::to_dict $tomlish] if [dict exists $data_dict $contextid] { #todo - nondestructive merge - don't destroy comments/formatting of existing records #if we use to_dict on the existing tomlish - we lose comments etc #also from_dict doesn't yet produce canonical nice-for-humans tomlish/toml #merge puts stderr "contextid '$contextid' exists in file $filepath" puts stderr "Merge not implemented.." set newfiledata "" } else { #append to existing toml data set newdict [dict create $contextid [dict get $contexts $contextid]] #we store our contexts in a structure already suitable for toml # (ie one where we tag strings,ints e.g {type STRING value "etc"}) set newtomlish [tomlish::from_dict $newdict] set newtoml [tomlish::to_toml $newtomlish] set newfiledata $existing_toml\n$newtoml } } else { set newdict [dict create $contextid [dict get $contexts $contextid]] set newtomlish [tomlish::from_dict $newdict] set newtoml [tomlish::to_toml $newtomlish] set newfiledata $newtoml } if {$newfiledata ne ""} { writeFile $filepath $newfiledata puts stderr "saved [string length $newfiledata] bytes to '$filepath'" } } namespace eval argdoc { set _page_options { -limit -default 100 -type integer -help\ "Each REST query returns a maximum number of results. This can be set to 0 to mean no limit - but it is still restricted to the max configured on the server. (1000?) This is effectively the page-size of the results. To retrieve more than a page, the next and previous urls can be iterated over." -offset -default 0 -type integer } set _create_update_options { -created -created__gte -created__lte -last_updated -last_updated__gte -last_updated__lte } set _tenant_options { -tenant_group_id -tenant_group_id__n -tenant_group -tenant_group__n -tenant_id -tenant_id__n -tenant -tenant__n } set _region_options { -region_id -region } set _site_options { -site_group_id -site_group_id__n -site_group -site_group__n -site_id -site_id__n -site -site__n } set _group_options { -group_id -group_id__n -group -group__n } set _contact_options { -contact -contact__n -contact_role -contact_role__n -contact_group -contact_group__n } set _role_options { -role_id -role_id__n -role -role__n } set _filter_string [list\ "ie \n Exact match\n(case-insensitive)"\ "nie \n Inverse exact match\n(case-insensitive)"\ "n \n Not equal to"\ "ic \n Contains\n (case-insensitive)"\ "nic \n Does not contain\n (case-insensitive)"\ "isw \n Starts with\n (case-insensitive)"\ "nisw \n Does not start with\n (case-insensitive)"\ "iew \n Ends with\n (case-insensitive)"\ "niew \n Does not end with\n (case-insensitive)"\ "empty \n Is empty/null"\ ] set _filter_number [list\ "n \n Not equal to"\ "lte \n Less than or equal"\ "lt \n Less than"\ "gte \n Greater than or equal"\ "gt \n Greater than"\ ] set _CUSTOM_PARAMS { -CUSTOM_PARAM -type list -minsize 2 -maxsize 2 -multiple 1 -help\ "Specify a parameter not in this API e.g -CUSTOM_PARAM {mytag blah}" } set _RETURN_PAGEDICT { -RETURN -type string -choices {dict showpagedict showpagedict2 json jsondump} -choicelabels { dict\ " Tcl dictionary (fastest)" showpagedict\ " human readable dict display with same order as dict." showpagedict2\ " human readable dict display results first, page metadata last." } -help\ "Options for returned data. Note that showdict results are relatively slow, especially for large resultsets" } set _RETURN_DICT { -RETURN -type string -choices {dict showdict showdict2 json jsondump} -choicelabels { dict\ " Tcl dictionary (fastest)" showdict\ " human readable dict display with same order as dict." showdict2\ " human readable dict display results first metadata last." } -help\ "Options for returned data. Note that showdict results are relatively slow, especially for large resultsets" } set _RETURN_LIST { -RETURN -type string -choices {list linelist showlist json jsondump} -choicelabels { list\ " Tcl list (fastest)" linelist\ " raw list with newline after each item" showlist\ " human readable list display" } -help\ "Options for returned data. Note that showlist results are relatively slow, especially for large resultsets" } set _RETURN_LISTOFDICTS { -RETURN -type string -choices {list linelist showlist json jsondump} -choicelabels { list\ " Tcl list (fastest)" linelist\ " raw list with newline after each item" showlistofdicts\ " human readable display list of dicts" } -help\ "Options for returned data. Note that showlist results are relatively slow, especially for large resultsets" } set _RETURN_STATUS { -RETURN -type string -default showdict2 -choices {dict showdict showdict2 json jsondump} -choicelabels { dict\ " Tcl dictionary" showdict\ " human readable dict display" showdict2\ " human readable dict display installed-apps first." } -help\ "Options for returned data." } set _name_filter_help "Paired search filter for name:\n" append _name_filter_help [textblock::list_as_table -columns 4 -show_hseps 1 $_filter_string] set _description_filter_help "Paired search filter for description:\n" append _description_filter_help [textblock::list_as_table -columns 4 -show_hseps 1 $_filter_string] set string_filter_help "Paired search filter for string:\n" append _string_filter_help [textblock::list_as_table -columns 4 -show_hseps 1 $_filter_string] #n, lte, lt, gte, gt #e.g virtualization/virtual-machine vcpus, memory, disk set number_filter_help "Paired search filter for number:\n" append _number_filter_help [textblock::list_as_table -columns 3 -show_hseps 1 $_filter_number] } punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::status @cmd -name punk::netbox::status -help\ "status_list GET request for endpoint /status/ Netbox's current operational status " @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_STATUS]\ { @values -min 0 -max 0 }] ::punk::netbox::system::make_rest_func ::punk::netbox::status api/status/ -verb get -body none #test function - todo use punk::netbox::system::make_rest_func #proc vrfs {args} { # set argd [punk::args::parse $args withid ::punk::netbox::vrfs] # lassign [dict values $argd] leaders opts values received # set apicontextid [dict get $leaders apicontextid] # set query [dict create] # dict for {k v} $opts { # if {$k eq "-CUSTOM_PARAM"} { # foreach custval $v { # lassign $custval param value # dict set query $param $value # } # } elseif {[string match *_FILTER $k]} { # set field [string range [string tolower [lindex [split $k _] 0]] 1 end] ;# -NAME_FILTER -> name # foreach fv $v { # lassign $fv filter value # dict set query ${field}__$filter $value # } # } else { # dict set query [string range $k 1 end] $v # } # } # variable contexts # if {![dict exists $contexts $apicontextid]} { # error "specified contextid '$apicontextid' not found" # } # set config [dict create\ # result json\ # ] # dict set config headers [list Authorization [list Token [dict get $contexts $apicontextid token value]]] # #variable headerdict # #set config [dict create\ # # headers $headerdict\ # # result json\ # #] # #variable url # set url [dict get $contexts $apicontextid url value] # puts "${url}api/ipam/vrfs/ '$query' '$config'" # rest::get ${url}api/ipam/vrfs/ $query $config #} #set ipam(vrfs) [dict create\ # url https://www.netbox1.intx.com.au/api/ipam/vrfs/\ # method get\ # result json\ # body none\ # headers $headerdict\ # opt_args {id: name: limit:100 offset:0} #] #set ipam(ip-addresses) [dict create\ # url https://www.netbox1.intx.com.au/api/ipam/ip-addresses/\ # method get\ # headers $headerdict\ # opt_args {parent: limit:100 offset:0} #] #set ipam(prefixes) [dict create\ # url https://www.netbox1.intx.com.au/api/ipam/prefixes/\ # method get\ # headers $headerdict\ # opt_args {prefix: limit:100 offset:0} #] #rest::create_interface ::punk::netbox::ipam #proc sample1 {p1 n args} { # #*** !doctools # #[call [fun sample1] [arg p1] [arg n] [opt {option value...}]] # #[para]Description of sample1 # #[para] Arguments: # # [list_begin arguments] # # [arg_def tring p1] A description of string argument p1. # # [arg_def integer n] A description of integer argument n. # # [list_end] # return "ok" #} #*** !doctools #[list_end] [comment {--- end definitions namespace punk::netbox ---}] } # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ tcl::namespace::eval punk::netbox::dcim { namespace export {[a-z]*} lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::dcim::devices_list @cmd -name punk::netbox::dcim::devices_list -help\ "tenancy_tenants_list GET request for endpoint /dcim/devices/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts -id -type integer -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -name -NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_name_filter_help}} -asset_tag -type string -ASSET_TAG_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -face -type string -face__n -type string -position -type integer -POSITION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -airflow -type string -airflow__n -type string -vc_position -type integer -VC_POSITION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -vc_priority -type integer -VC_PRIORITY_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} }\ [set ::punk::netbox::argdoc::_create_update_options]\ { -q -type string -tag -type string -tag__n -type string }\ [set ::punk::netbox::argdoc::_tenant_options]\ [set ::punk::netbox::argdoc::_contact_options]\ { -local_context_data -manufacturer_id -manufacturer_id__n -manufacturer -manufacturer__n -device_type_id -device_type_id__n -role_id -role_id__n -role -role__n -parent_device_id -parent_device_id__n -platform_id -platform_id__n -platform -platform__n }\ [set ::punk::netbox::argdoc::_group_options]\ [set ::punk::netbox::argdoc::_region_options]\ [set ::punk::netbox::argdoc::_site_options]\ { -location_id -type integer -location_id__n -type integer -rack_id -type integer -rack_id__n -type integer -cluster_id -type integer -cluster_id__n -type integer -model -type string -model__n -type string -status -type string -status__n -type string -mac_address -type string -MAC_ADDRESS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -serial -type string -SERIAL_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -virtual_chassis_id -type integer -virtual_chassis_id__n -type integer }\ [set ::punk::netbox::argdoc::_page_options]\ [set ::punk::netbox::argdoc::_CUSTOM_PARAMS]\ [set ::punk::netbox::argdoc::_RETURN_PAGEDICT]\ { @values -min 0 -max 0 }] ::punk::netbox::system::make_rest_func ::punk::netbox::dcim::devices_list api/dcim/devices/ -verb get -body none } tcl::namespace::eval punk::netbox::ipam { namespace export {[a-z]*} lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::ipam::vrfs_list @cmd -name punk::netbox::ipam::vrfs_list -help\ "ipam_vrfs_list GET request for endpoint /ipam/vrfs/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts -id -type integer -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -name -NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_name_filter_help}} -rd -type string -help\ "Route distinguisher in any format" -enforce_unique -description -type string -help "Exact Match (case sensitive)" -DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_description_filter_help}} }\ [set ::punk::netbox::argdoc::_create_update_options]\ { -q -tag }\ [set ::punk::netbox::argdoc::_tenant_options]\ [set ::punk::netbox::argdoc::_region_options]\ [set ::punk::netbox::argdoc::_site_options]\ [set ::punk::netbox::argdoc::_group_options]\ [set ::punk::netbox::argdoc::_role_options]\ { -status -available_on_device -available_on_virtualmachine }\ [set ::punk::netbox::argdoc::_page_options]\ [set ::punk::netbox::argdoc::_CUSTOM_PARAMS]\ [set ::punk::netbox::argdoc::_RETURN_PAGEDICT]\ { @values -min 0 -max 0 }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::vrfs_list api/ipam/vrfs/ -verb get -body none lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::ipam::vrfs_read @cmd -name punk::netbox::ipam::vrfs_read -help\ "ipam_vrfs_list GET request for endpoint /ipam/vrfs/{id}" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 1 -max 1 id -type integer -help\ "A unique integer value identifying this VRF" }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::vrfs_read api/ipam/vrfs/{id}/ -verb get -body none punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::prefixes_list @cmd -name punk::netbox::ipam::prefixes_list -help\ "ipam_prefixes_list GET request for endpoint /ipam/prefixes/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts -id -type integer -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -is_pool -mark_utilized -description -type string -help "Exact Match (case sensitive)" -DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_description_filter_help}} }\ [set ::punk::netbox::argdoc::_create_update_options]\ { -q -type string -help\ "Query prefixes by substring" -tag }\ [set ::punk::netbox::argdoc::_tenant_options]\ [set ::punk::netbox::argdoc::_region_options]\ [set ::punk::netbox::argdoc::_site_options]\ [set ::punk::netbox::argdoc::_group_options]\ [set ::punk::netbox::argdoc::_role_options]\ { -family -prefix -within -within_include -contains -depth -DEPTH_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -children -CHILDREN_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -mask_length -mask_length__gte -mask_length__lte -vlan_id -type integer -vlan_id__n -type integer -vlan_vid -type integer -VLAN_VID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -vrf_id -vrf -status -available_on_device -available_on_virtualmachine }\ [set ::punk::netbox::argdoc::_page_options]\ [set ::punk::netbox::argdoc::_CUSTOM_PARAMS]\ [set ::punk::netbox::argdoc::_RETURN_PAGEDICT]\ { @values -min 0 -max 0 }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::prefixes_list api/ipam/prefixes/ -verb get -body none punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::prefixes_create @cmd -name punk::netbox::ipam::prefixes_create -help\ "ipam_prefixes_create POST request for endpoint /ipam/prefixes/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 1 -max 1 body -type string -help\ "JSON string" }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::prefixes_create api/ipam/prefixes/{id}/ -verb post -body required punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::prefixes_read @cmd -name punk::netbox::ipam::prefixes_read -help\ "ipam_prefixes_read GET request for endpoint /ipam/prefixes/{id}/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 1 -max 1 id -type integer -help\ "A unique integer value identifying this prefix" }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::prefixes_read api/ipam/prefixes/{id}/ -verb get -body none punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::prefixes_available-ips_list @cmd -name punk::netbox::ipam::prefixes_available-ips_list -help\ "ipam_prefixes_available-ips_list GET request for endpoint /ipam/prefixes/{id}/available-ips/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_page_options]\ [set ::punk::netbox::argdoc::_CUSTOM_PARAMS]\ [set ::punk::netbox::argdoc::_RETURN_LISTOFDICTS]\ { @values -min 1 -max 1 id -type integer -help\ "A unique integer value identifying this prefix" }\ ] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::prefixes_available-ips_list api/ipam/prefixes/{id}/available-ips/ -verb get -body none punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::prefixes_available-ips_create @cmd -name punk::netbox::ipam::prefixes_available-ips_create -help\ "ipam_prefixes_available-ips_create POST request for endpoint /ipam/prefixes/{id}/available-ips/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_CUSTOM_PARAMS]\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 1 -max 2 id -type integer -help\ "A unique integer value identifying this prefix" body -type string -default "" -help\ { If empty create a single IP with default values. (next available IP in prefix) Create 2 IPs: [ {"description": "ip1"}, {"description": "ip2"} ] NOTE: This always uses next available IPs. To create a specific IP, use api/ipam/ip-addresses endpoint. The returned json is just an object if one address created, but a list if multiple. :/ } }\ ] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::prefixes_available-ips_create api/ipam/prefixes/{id}/available-ips/ -verb post -body required punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::ip-addresses_list @cmd -name punk::netbox::ipam::ip-addresses_list -help\ "ipam_ip-addresses_list GET request for endpoint /ipam/ip-addresses/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts -id -type integer -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -dns_name -DNS_NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -description -type string -help "Exact Match (case sensitive)" -DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_description_filter_help}} }\ [set ::punk::netbox::argdoc::_create_update_options]\ { -q -tag }\ [set ::punk::netbox::argdoc::_tenant_options]\ [set ::punk::netbox::argdoc::_region_options]\ [set ::punk::netbox::argdoc::_site_options]\ [set ::punk::netbox::argdoc::_group_options]\ [set ::punk::netbox::argdoc::_role_options]\ { -family -parent -address -mask_length -vrf_id -vrf -present_in_vrf_id -present_in_vrf -device -device_id -virtual_machine -virtual_machine_id -interface -interface_id -vminterface -vminterface_id -fhrpgroup_id -assigned_to_interface -status -role -available_on_device -available_on_virtualmachine }\ [set ::punk::netbox::argdoc::_page_options]\ [set ::punk::netbox::argdoc::_CUSTOM_PARAMS]\ [set ::punk::netbox::argdoc::_RETURN_PAGEDICT]\ { @values -min 0 -max 0 }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::ip-addresses_list api/ipam/ip-addresses/ -verb get -body none punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::ip-addresses_read @cmd -name punk::netbox::ipam::ip-addresses_read -help\ "ipam_ip-addresses_read GET request for endpoint /ipam/ip-addresses/{id}/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 1 -max 1 id -type integer }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::ip-addresses_read api/ipam/ip-addresses/{id}/ -verb get -body none punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::ip-addresses_create @cmd -name punk::netbox::ipam::ip-addresses_create -help\ "ipam_ip-addresses_create POST request for endpoint /ipam/ip-addresses/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 1 -max 1 body -type string -help\ {JSON string Example: { "address": "string", "vrf": 0, "tenant": 0, "status": "active", "role": "loopback", "assigned_object_type": "string", "assigned_object_id": 0, "nat_inside": 0, "dns_name": "string", "description": "string", "tags": [ { "name": "string", "slug": "string", "color": "string" } ], "custom_fields": {} } Required: address (IPv4 or IPV6 address with mask) } }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::ip-addresses_create api/ipam/ip-addresses/ -verb post -body required punk::args::define {*}[list\ { @dynamic @id -id ::punk::netbox::ipam::ip-addresses_bulk_partial_update @cmd -name punk::netbox::ipam::ip-addresses_bulk_partial_update -help\ "ipam_ip-addresses_bulk_partical_update PATCH request for endpoint /ipam/ip-addresses/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 1 -max 1 body -type string -help\ {JSON string model: { "address": "string", "vrf": 0, "tenant": 0, "status": "active", "role": "loopback", "assigned_object_type": "string", "assigned_object_id": 0, "nat_inside": 0, "dns_name": "string", "description": "string", "tags": [ { "name": "string", "slug": "string", "color": "string" } ], "custom_fields": {} } required: address } }] ::punk::netbox::system::make_rest_func ::punk::netbox::ipam::ip-addresses_bulk_partial_update api/ipam/ip-addresses/ -verb patch -body required } tcl::namespace::eval punk::netbox::tenancy { namespace export {[a-z]*} lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::tenancy::tenants_list @cmd -name punk::netbox::tenancy::tenants_list -help\ "tenancy_tenants_list GET request for endpoint /tenancy/tenants/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts -id -type integer -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -name -NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_name_filter_help}} -slug -type string -SLUG_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -description -type string -DESCRIPTION_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} }\ [set ::punk::netbox::argdoc::_create_update_options]\ { -q -type string -tag -type string -tag__n -type string }\ [set ::punk::netbox::argdoc::_tenant_options]\ [set ::punk::netbox::argdoc::_contact_options]\ { }\ { }\ [set ::punk::netbox::argdoc::_group_options]\ { }\ [set ::punk::netbox::argdoc::_page_options]\ [set ::punk::netbox::argdoc::_CUSTOM_PARAMS]\ [set ::punk::netbox::argdoc::_RETURN_PAGEDICT]\ { @values -min 0 -max 0 }] ::punk::netbox::system::make_rest_func ::punk::netbox::tenancy::tenants_list api/tenancy/tenants/ -verb get -body none } tcl::namespace::eval punk::netbox::virtualization { namespace export {[a-z]*} lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::virtualization::virtual-machines_list @cmd -name punk::netbox::virtualization::virtual-machines_list -help\ "virtualization_virtual-machines_list GET request for endpoint /virtualization/virtual-machines/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts -id -type integer -ID_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -name -NAME_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_name_filter_help}} -cluster -type string -cluster_n -type string -vcpus -type integer -VCPUS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -memory -type integer -help\ "Whole number" -MEMORY_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} -disk -type integer -DISK_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_number_filter_help}} }\ [set ::punk::netbox::argdoc::_create_update_options]\ { -q -tag }\ [set ::punk::netbox::argdoc::_tenant_options]\ [set ::punk::netbox::argdoc::_contact_options]\ { -local_context_data -status -status_n -cluster_group_id -cluster_group_id__n -cluster_group -cluster_group__n -cluster_type_id -cluster_type_id__n -cluster_type -cluster_type__n -cluster_id -cluster_id__n }\ [set ::punk::netbox::argdoc::_region_options]\ [set ::punk::netbox::argdoc::_site_options]\ { -platform -platform__n -mac_address -MAC_ADDRESS_FILTER -type list -minsize 2 -maxsize 2 -multiple 1 -help {${$::punk::netbox::argdoc::_string_filter_help}} -has_primary_ip }\ [set ::punk::netbox::argdoc::_group_options]\ [set ::punk::netbox::argdoc::_role_options]\ { }\ [set ::punk::netbox::argdoc::_page_options]\ [set ::punk::netbox::argdoc::_CUSTOM_PARAMS]\ [set ::punk::netbox::argdoc::_RETURN_PAGEDICT]\ { @values -min 0 -max 0 }] ::punk::netbox::system::make_rest_func ::punk::netbox::virtualization::virtual-machines_list api/virtualization/virtual-machines/ -verb get -body none lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::virtualization::virtual-machines_create @cmd -name punk::netbox::virtualization::virtual-machines_create -help\ "virtualization_virtual-machines_create GET request for endpoint /virtualization/virtual-machines/" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 2 -max 2 id -type integer -help\ "A unique integer value identifying this virtual machine" body -type string -help\ "JSON string" }] ::punk::netbox::system::make_rest_func ::punk::netbox::virtualization::virtual-machines_create api/virtualization/virtual-machines/ -verb post -body required lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::virtualization::virtual-machines_delete @cmd -name punk::netbox::virtualization::virtual-machines_delete -help\ "virtualization_virtual-machines_delete DELETE request for endpoint /virtualization/virtual-machines/ HTTP code: 204 " @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts -FORCE -default 0 -type boolean -help\ "Set to true to BULK delete all items at this endpoint" }\ { @values -min 0 -max 0 }] ::punk::netbox::system::make_rest_func ::punk::netbox::virtualization::virtual-machines_delete api/virtualization/virtual-machines/ -verb delete -body none lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::virtualization::virtual-machines_read @cmd -name punk::netbox::virtualization::virtual-machines_read -help\ "virtualization_virtual-machines_read GET request for endpoint /virtualization/virtual-machines/{id}" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 1 -max 1 id -type integer -help\ "A unique integer value identifying this virtual machine" }] ::punk::netbox::system::make_rest_func ::punk::netbox::virtualization::virtual-machines_read api/virtualization/virtual-machines/{id}/ -verb get -body none lappend PUNKARGS [list\ { @dynamic @id -id ::punk::netbox::virtualization::virtual-machines_update @cmd -name punk::netbox::virtualization::virtual-machines_update -help\ "virtualization_virtual-machines_update PUT request for endpoint /virtualization/virtual-machines/{id}" @leaders -min 1 -max 1 apicontextid -help\ "The name of the stored api context to use. A contextid can be created in-memory using api_context_create, or loaded from a .toml file using api_context_load."\ -choices {${[punk::netbox::api_context_names]}} @opts }\ [set ::punk::netbox::argdoc::_RETURN_DICT]\ { @values -min 2 -max 2 id -type integer -help\ "A unique integer value identifying this virtual machine" body -type string -help\ "JSON string" }] ::punk::netbox::system::make_rest_func ::punk::netbox::virtualization::virtual-machines_update api/virtualization/virtual-machines/{id}/ -verb put -body required } # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # Secondary API namespace # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ tcl::namespace::eval punk::netbox::lib { tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase tcl::namespace::path [tcl::namespace::parent] #*** !doctools #[subsection {Namespace punk::netbox::lib}] #[para] Secondary functions that are part of the API #[list_begin definitions] #proc utility1 {p1 args} { # #*** !doctools # #[call lib::[fun utility1] [arg p1] [opt {?option value...?}]] # #[para]Description of utility1 # return 1 #} #*** !doctools #[list_end] [comment {--- end definitions namespace punk::netbox::lib ---}] } # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # == === === === === === === === === === === === === === === # Sample 'about' function with punk::args documentation # == === === === === === === === === === === === === === === tcl::namespace::eval punk::netbox { tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase variable PUNKARGS variable PUNKARGS_aliases lappend PUNKARGS [list { @id -id "(package)punk::netbox" @package -name "punk::netbox" -help\ "Package Description" }] namespace eval argdoc { #namespace for custom argument documentation proc package_name {} { return punk::netbox } proc about_topics {} { #info commands results are returned in an arbitrary order (like array keys) set topic_funs [info commands [namespace current]::get_topic_*] set about_topics [list] foreach f $topic_funs { set tail [namespace tail $f] lappend about_topics [string range $tail [string length get_topic_] end] } #Adjust this function or 'default_topics' if a different order is required return [lsort $about_topics] } proc default_topics {} {return [list Description *]} # ------------------------------------------------------------- # get_topic_ functions add more to auto-include in about topicg # ------------------------------------------------------------- proc get_topic_Description {} { punk::args::lib::tstr [string trim { package punk::netbox A library for calling netbox REST functions } \n] } proc get_topic_License {} { return "MIT" } proc get_topic_Version {} { return "$::punk::netbox::version" } proc get_topic_Contributors {} { set authors {{Julian Noble }} set contributors "" foreach a $authors { append contributors $a \n } if {[string index $contributors end] eq "\n"} { set contributors [string range $contributors 0 end-1] } return $contributors } proc get_topic_features {} { punk::args::lib::tstr -return string { netbox /status/ endpoint beginnings of /ipam/ endpoints beginnings of /virtualization/ endpoints } } # ------------------------------------------------------------- } # we re-use the argument definition from punk::args::standard_about and override some items set overrides [dict create] dict set overrides @id -id "::punk::netbox::about" dict set overrides @cmd -name "punk::netbox::about" dict set overrides @cmd -help [string trim [punk::args::lib::tstr { About punk::netbox }] \n] dict set overrides topic -choices [list {*}[punk::netbox::argdoc::about_topics] *] dict set overrides topic -choicerestricted 1 dict set overrides topic -default [punk::netbox::argdoc::default_topics] ;#if -default is present 'topic' will always appear in parsed 'values' dict set newdef [punk::args::resolved_def -antiglobs -package_about_namespace -override $overrides ::punk::args::package::standard_about *] lappend PUNKARGS [list $newdef] proc about {args} { package require punk::args #standard_about accepts additional choices for topic - but we need to normalize any abbreviations to full topic name before passing on set argd [punk::args::parse $args withid ::punk::netbox::about] lassign [dict values $argd] _leaders opts values _received punk::args::package::standard_about -package_about_namespace ::punk::netbox::argdoc {*}$opts {*}[dict get $values topic] } } # end of sample 'about' function # == === === === === === === === === === === === === === === # ----------------------------------------------------------------------------- # register namespace(s) to have PUNKARGS,PUNKARGS_aliases variables checked # ----------------------------------------------------------------------------- # variable PUNKARGS # variable PUNKARGS_aliases namespace eval ::punk::args::register { #use fully qualified so 8.6 doesn't find existing var in global namespace lappend ::punk::args::register::NAMESPACES\ ::punk::netbox\ ::punk::netbox::dcim\ ::punk::netbox::ipam\ ::punk::netbox::tenancy\ ::punk::netbox::virtualization } # ----------------------------------------------------------------------------- # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Ready package provide punk::netbox [tcl::namespace::eval punk::netbox { variable pkg punk::netbox variable version set version 999999.0a1.0 }] return #*** !doctools #[manpage_end]