From 89a5d96e64c76f306bf740cd643ce70d2da9d1d2 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Fri, 26 Nov 2021 11:09:27 +0100 Subject: [PATCH 01/15] Migrate to new client style --- clusters.go | 183 +++++++++++++++++ device_roles.go | 111 +++++----- device_types.go | 176 +++++++++++----- netbox_devices.go => devices.go | 177 ++++++---------- netbox_interfaces.go => interfaces.go | 122 ++++------- inventory.go | 108 ++++++++++ netbox.go | 268 ++++++++++++++++++++++-- netbox_inventory.go | 152 -------------- netbox_prefixes.go | 217 -------------------- netbox_site_groups.go | 157 -------------- netbox_tenants.go | 167 --------------- netbox_virtualization.go | 284 -------------------------- netbox_vlans.go | 240 ---------------------- netbox_vrfs.go | 161 --------------- prefixes.go | 282 +++++++++++++++++++++++++ rear_ports.go | 75 +++---- netbox_secrets.go => secrets.go | 81 +++----- site_groups.go | 151 ++++++++++++++ netbox_sites.go => sites.go | 168 ++++++++------- tenants.go | 145 +++++++++++++ virtual_machines.go | 106 ++++++++++ vlans.go | 172 ++++++++++++++++ vrfs.go | 138 +++++++++++++ 23 files changed, 1961 insertions(+), 1880 deletions(-) create mode 100644 clusters.go rename netbox_devices.go => devices.go (81%) rename netbox_interfaces.go => interfaces.go (64%) create mode 100644 inventory.go delete mode 100644 netbox_inventory.go delete mode 100644 netbox_prefixes.go delete mode 100644 netbox_site_groups.go delete mode 100644 netbox_tenants.go delete mode 100644 netbox_virtualization.go delete mode 100644 netbox_vlans.go delete mode 100644 netbox_vrfs.go create mode 100644 prefixes.go rename netbox_secrets.go => secrets.go (55%) create mode 100644 site_groups.go rename netbox_sites.go => sites.go (56%) create mode 100644 tenants.go create mode 100644 virtual_machines.go create mode 100644 vlans.go create mode 100644 vrfs.go diff --git a/clusters.go b/clusters.go new file mode 100644 index 0000000..675859d --- /dev/null +++ b/clusters.go @@ -0,0 +1,183 @@ +package netboxgo + +import ( + "context" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/gorilla/schema" +) + +type ClustersService service + +// NewCluster is used to create new VirtualizationClusters +type NewCluster struct { + ID int `json:"id"` + Name string `json:"name"` + Type struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + ClusterCount int `json:"cluster_count"` + } `json:"type"` + Group struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + ClusterCount int `json:"cluster_count"` + } `json:"group"` + Site struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"site"` + Comments string `json:"comments"` + Tags []struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + Color string `json:"color"` + } `json:"tags"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` + DeviceCount int `json:"device_count"` + VirtualmachineCount int `json:"virtualmachine_count"` +} + +// Clusters is used to list VirtualizationClusters +type Clusters struct { + Count int `json:"count"` + Next string `json:"next"` + Previous string `json:"previous"` + Results []struct { + ID int `json:"id"` + Name string `json:"name"` + Type struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + ClusterCount int `json:"cluster_count"` + } `json:"type"` + Group struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + ClusterCount int `json:"cluster_count"` + } `json:"group"` + Site struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"site"` + Comments string `json:"comments"` + Tags []struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + Color string `json:"color"` + } `json:"tags"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` + DeviceCount int `json:"device_count"` + VirtualmachineCount int `json:"virtualmachine_count"` + } `json:"results"` +} + +// ClusterFilter is used to filter out VirtualizationClusters +type ClusterFilter struct { + Offset int64 `schema:"offset,omitempty"` + Limit int64 `schema:"limit,omitempty"` + + // User specific filters + Name string `schema:"name,omitempty"` + Group string `schema:"group,omitempty"` + GroupID string `schema:"group_id,omitempty"` + TypeID string `schema:"type_id,omitempty"` + Type string `schema:"type,omitempty"` + SiteID string `schema:"site_id,omitempty"` + Site string `schema:"site,omitempty"` + Tenant string `schema:"tenant,omitempty"` + IDIn string `schema:"id__in,omitempty"` + Q string `schema:"q,omitempty"` + Tag string `schema:"tag,omitempty"` +} + +const clustersPath = "/virtualization/clusters" + +// List clusters. ClusterFilter is used to list based on filter queries. +func (s *ClustersService) List(ctx context.Context, f *ClusterFilter) (*Clusters, error) { + var clusters Clusters + var query string + var req *http.Request + var err error + + encoder := schema.NewEncoder() + + form := url.Values{} + err = encoder.Encode(f, form) + if err != nil { + return &clusters, err + } + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", clustersPath, query, nil) + if err != nil { + return &clusters, err + } + + _, err = s.client.do(req, &clusters) + if err != nil { + return &clusters, err + } + + return &clusters, nil +} + +// Create a cluster +func (s *ClustersService) Create(ctx context.Context, c *NewCluster) error { + var err error + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", clustersPath, "", c) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + _, err = s.client.do(req, nil) + if err != nil { + return fmt.Errorf("unable to do request: %w", err) + } + + return nil +} + +// // Update a cluster +// func (s *ClustersService) Update(ctx context.Context, id string, c *UpdateCluster) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", clustersPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil diff --git a/device_roles.go b/device_roles.go index f5013f9..7bb75c2 100644 --- a/device_roles.go +++ b/device_roles.go @@ -1,18 +1,16 @@ package netboxgo import ( - "crypto/tls" - "encoding/json" - "io/ioutil" + "context" "net/http" "net/url" - "time" "github.com/gorilla/schema" - "github.com/pkg/errors" ) -type ListDeviceRoles struct { +type DeviceRolesService service + +type DeviceRoles struct { Count int `json:"count"` Next string `json:"next"` Previous string `json:"previous"` @@ -45,58 +43,69 @@ type DeviceRoleFilter struct { Q string `schema:"q,omitempty"` } -// ListDeviceTypes method returns dcim_device_roles from Netbox API -func (n *NetBox) ListDeviceRoles(d *ListDeviceRoles, f *DeviceRoleFilter) error { +const deviceRolesPath = "/dcim/device-roles" + +// List deviceroles. DeviceRoleFilter is used to list based on filter queries. +func (s *DeviceRolesService) List(ctx context.Context, f *DeviceRoleFilter) (*DeviceRoles, error) { + var deviceroles DeviceRoles + var query string + var req *http.Request + var err error + encoder := schema.NewEncoder() - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - deviceurl := n.RootURL + "/api/dcim/device-roles/" - if f != nil { - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - deviceurl = deviceurl + "?" + query - } - var request *http.Request - var err error - request, err = http.NewRequest("GET", deviceurl, nil) + form := url.Values{} + err = encoder.Encode(f, form) if err != nil { - return err + return &deviceroles, err } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", deviceRolesPath, query, nil) if err != nil { - return err + return &deviceroles, err } - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d (%s)\n", response.StatusCode, http.StatusOK, deviceurl) + _, err = s.client.do(req, &deviceroles) + if err != nil { + return &deviceroles, err } - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &d) - if err != nil { - return err - } - return nil + return &deviceroles, nil } + +// var err error +// var req *http.Request + +// req, err = s.client.newRequest(ctx, "POST", deviceRolesPath, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } + +// // Update a device-role +// func (s *DeviceRolesService) Update(ctx context.Context, id string, c *UpdateDevice) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", deviceRolesPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } diff --git a/device_types.go b/device_types.go index 923c1dd..2a3f2ca 100644 --- a/device_types.go +++ b/device_types.go @@ -1,18 +1,17 @@ package netboxgo import ( - "crypto/tls" - "encoding/json" - "io/ioutil" + "context" "net/http" "net/url" "time" "github.com/gorilla/schema" - "github.com/pkg/errors" ) -type ListDeviceTypes struct { +type DeviceTypesService service + +type DeviceTypes struct { Count int `json:"count"` Next string `json:"next"` Previous string `json:"previous"` @@ -49,11 +48,10 @@ type DeviceType struct { Slug string `json:"slug"` Color string `json:"color"` } `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - DeviceCount int `json:"device_count"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` + DeviceCount int `json:"device_count"` } // DeviceTypeFilter is used to filter dcim_device_types_list query to the Netbox API @@ -72,58 +70,126 @@ type DeviceTypeFilter struct { Tag string `schema:"tag,omitempty"` } -// ListDeviceTypes method returns dcim_device_types_list from Netbox API -func (n *NetBox) ListDeviceTypes(d *ListDeviceTypes, f *DeviceTypeFilter) error { +const deviceTypesPath = "/dcim/device-types" + +// List device-types. DeviceTypeFilter is used to list based on filter queries. +func (s *DeviceTypesService) List(ctx context.Context, f *DeviceTypeFilter) (*DeviceTypes, error) { + var devicetypes DeviceTypes + var query string + var req *http.Request + var err error + encoder := schema.NewEncoder() - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - deviceurl := n.RootURL + "/api/dcim/device-types/" - if f != nil { - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - deviceurl = deviceurl + "?" + query - } - var request *http.Request - var err error - request, err = http.NewRequest("GET", deviceurl, nil) + form := url.Values{} + err = encoder.Encode(f, form) if err != nil { - return err + return &devicetypes, err } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", deviceTypesPath, query, nil) if err != nil { - return err + return &devicetypes, err } - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d (%s)\n", response.StatusCode, http.StatusOK, deviceurl) + _, err = s.client.do(req, &devicetypes) + if err != nil { + return &devicetypes, err } - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &d) - if err != nil { - return err - } - return nil + return &devicetypes, nil } + +// // Create a device +// func (s *DeviceTypesService) Create(ctx context.Context, c *NewDeviceType) error { +// var err error +// var req *http.Request + +// req, err = s.client.newRequest(ctx, "POST", deviceTypesPath, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } + +// // Update a device +// func (s *DeviceTypesService) Update(ctx context.Context, id string, c *UpdateDevice) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", deviceTypesPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } +// // ListDeviceTypes method returns dcim_device_types_list from Netbox API +// func (n *NetBox) ListDeviceTypes(d *DeviceTypes, f *DeviceTypeFilter) error { +// encoder := schema.NewEncoder() + +// transport := &http.Transport{ +// TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, +// } +// timeout := time.Duration(60 * time.Second) +// client := &http.Client{ +// Timeout: timeout, +// Transport: transport, +// } +// deviceurl := n.RootURL + "/api/dcim/device-types/" +// if f != nil { +// form := url.Values{} +// err := encoder.Encode(f, form) +// if err != nil { +// return err +// } +// query := form.Encode() +// deviceurl = deviceurl + "?" + query +// } +// var request *http.Request +// var err error +// request, err = http.NewRequest("GET", deviceurl, nil) +// if err != nil { +// return err +// } +// request.Header.Add("Accept", "application/json") +// request.Header.Add("Authorization", " Token "+n.Token) +// response, err := client.Do(request) +// if err != nil { +// return err +// } + +// if response.StatusCode != http.StatusOK { +// return errors.Errorf("Error: response was: %d should be %d (%s)\n", response.StatusCode, http.StatusOK, deviceurl) +// } + +// data, err := ioutil.ReadAll(response.Body) +// if err != nil { +// return err +// } + +// err = response.Body.Close() +// if err != nil { +// return err +// } + +// err = json.Unmarshal(data, &d) +// if err != nil { +// return err +// } +// return nil +// } diff --git a/netbox_devices.go b/devices.go similarity index 81% rename from netbox_devices.go rename to devices.go index 795392d..84f982e 100644 --- a/netbox_devices.go +++ b/devices.go @@ -1,21 +1,19 @@ package netboxgo import ( - "bytes" - "crypto/tls" - "encoding/json" - "io/ioutil" + "context" + "fmt" "net/http" "net/url" - "strconv" "time" "github.com/gorilla/schema" - "github.com/pkg/errors" ) -// DcimDevicesList is used for Netbox dcim_device_list return struct -type DcimDevicesList struct { +type DevicesService service + +// Devices is used for Netbox dcim_device_list return struct +type Devices struct { Count int `json:"count"` Next string `json:"next"` Previous string `json:"previous"` @@ -172,7 +170,7 @@ type Device struct { LastUpdated time.Time `json:"last_updated"` } -type DcimCreateDevice struct { +type NewDevice struct { Name string `json:"name,omitempty,omitempty"` DeviceType int `json:"device_type,omitempty,omitempty"` DeviceRole int `json:"device_role,omitempty,omitempty"` @@ -230,7 +228,7 @@ type DcimCreateDevice struct { } `json:"custom_fields,omitempty"` } -type DcimUpdateDevice struct { +type UpdateDevice struct { Name string `json:"name,omitempty"` DeviceType int `json:"device_type,omitempty"` DeviceRole int `json:"device_role,omitempty"` @@ -312,121 +310,70 @@ type DeviceFilter struct { Tag string `schema:"tag,omitempty"` } -// ListDevices method returns dcim_device_list from Netbox API -func (n *NetBox) ListDevices(d *DcimDevicesList, f *DeviceFilter) error { +const devicesPath = "/dcim/devices" + +// List devices. DeviceFilter is used to list based on filter queries. +func (s *DevicesService) List(ctx context.Context, f *DeviceFilter) (*Devices, error) { + var devices Devices + var query string + var req *http.Request + var err error + encoder := schema.NewEncoder() - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, + form := url.Values{} + err = encoder.Encode(f, form) + if err != nil { + return &devices, err } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", devicesPath, query, nil) + if err != nil { + return &devices, err } - deviceurl := n.RootURL + "/api/dcim/devices/" - if f != nil { - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - deviceurl = deviceurl + "?" + query + + _, err = s.client.do(req, &devices) + if err != nil { + return &devices, err } - var request *http.Request + + return &devices, nil +} + +// Create a device +func (s *DevicesService) Create(ctx context.Context, c *NewDevice) error { var err error - request, err = http.NewRequest("GET", deviceurl, nil) + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", devicesPath, "", c) if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err + return fmt.Errorf("unable to create request: %w", err) } - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d (%s)\n", response.StatusCode, http.StatusOK, deviceurl) - } - - data, err := ioutil.ReadAll(response.Body) + _, err = s.client.do(req, nil) if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &d) - if err != nil { - return err - } - return nil -} - -func (n *NetBox) CreateDevice(v *DcimCreateDevice) error { - data, err := json.Marshal(v) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("POST", n.RootURL+"/api/dcim/devices/", bytes.NewBuffer(data)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - err = response.Body.Close() - if err != nil { - return err - } - - if response.StatusCode == http.StatusCreated { - return nil - } - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) -} - -func (n *NetBox) UpdateDevice(v *DcimUpdateDevice, id int) error { - data, err := json.Marshal(v) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("PATCH", n.RootURL+"/api/dcim/devices/"+strconv.Itoa(id)+"/", bytes.NewBuffer(data)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - - _, err = client.Do(request) - if err != nil { - return err + return fmt.Errorf("unable to do request: %w", err) + } + + return nil +} + +// Update a device +func (s *DevicesService) Update(ctx context.Context, id string, c *UpdateDevice) error { + var req *http.Request + var err error + + path := fmt.Sprintf("%s/%s", devicesPath, id) + + req, err = s.client.newRequest(ctx, "PATCH", path, "", c) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + _, err = s.client.do(req, nil) + if err != nil { + return fmt.Errorf("unable to do request: %w", err) } return nil diff --git a/netbox_interfaces.go b/interfaces.go similarity index 64% rename from netbox_interfaces.go rename to interfaces.go index eb040cb..2be934e 100644 --- a/netbox_interfaces.go +++ b/interfaces.go @@ -1,22 +1,20 @@ package netboxgo import ( - "bytes" - "crypto/tls" - "encoding/json" - - // "fmt" - "io/ioutil" + "context" + "fmt" "net/http" "net/url" - "time" + + // "fmt" "github.com/gorilla/schema" - "github.com/pkg/errors" ) -// DcimInterfacesCreate is used for the return values from Netbox API dcim_interfaces_create -type DcimInterfacesCreate struct { +type InterfacesService service + +// NewInterface is used for the return values from Netbox API dcim_interfaces_create +type NewInterface struct { Device int `json:"device"` Name string `json:"name"` Type int `json:"type,omitempty"` @@ -36,8 +34,8 @@ type DcimInterfacesCreate struct { Tags []string `json:"tags,omitempty"` } -// DcimInterfacesList is used for the return value from NetBox API dcim_interfaces_list -type DcimInterfacesList struct { +// Interfaces is used for the return value from NetBox API dcim_interfaces_list +type Interfaces struct { Count int `json:"count,omitempty"` Next interface{} `json:"next,omitempty"` Previous interface{} `json:"previous,omitempty"` @@ -93,7 +91,7 @@ type InterfaceFilter struct { Offset int64 `schema:"offset,omitempty"` Limit int64 `schema:"limit,omitempty"` - //User specific filters + // User specific filters ID string `schema:"id,omitempty"` Name string `schema:"name,omitempty"` ConnectionStatus string `schema:"connection_status,omitempty"` @@ -114,89 +112,51 @@ type InterfaceFilter struct { VLAN string `schema:"vlan,omitempty"` } -// ListInterfaces returns Netbox dcim_interfaces_list -func (n *NetBox) ListInterfaces(i *DcimInterfacesList, f *InterfaceFilter) error { - var encoder = schema.NewEncoder() +const interfacesPath = "/dcim/interfaces" + +// List devices. DeviceFilter is used to list based on filter queries. +func (s *InterfacesService) List(ctx context.Context, f *InterfaceFilter) (*Interfaces, error) { + var interfaces Interfaces + var query string + var req *http.Request + var err error + + encoder := schema.NewEncoder() form := url.Values{} - err := encoder.Encode(f, form) + err = encoder.Encode(f, form) if err != nil { - return err + return &interfaces, err } - query := form.Encode() + query = form.Encode() - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/dcim/interfaces/?"+query, nil) + req, err = s.client.newRequest(ctx, "GET", interfacesPath, query, nil) if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err + return &interfaces, err } - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) + _, err = s.client.do(req, &interfaces) + if err != nil { + return &interfaces, err } - data, err := ioutil.ReadAll(response.Body) + return &interfaces, nil +} + +// Create a interfaces +func (s *InterfacesService) Create(ctx context.Context, c *NewInterface) error { + var err error + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", interfacesPath, "", c) if err != nil { - return err + return fmt.Errorf("unable to create request: %w", err) } - err = response.Body.Close() + _, err = s.client.do(req, nil) if err != nil { - return err + return fmt.Errorf("unable to do request: %w", err) } - err = json.Unmarshal(data, &i) - if err != nil { - return err - } return nil } - -// CreateInterfaces creates interfaces via Netbox API dcim_interfaces_create -func (n *NetBox) CreateInterfaces(i *DcimInterfacesCreate) error { - interfaceData, err := json.Marshal(i) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("POST", n.RootURL+"/api/dcim/interfaces/", bytes.NewBuffer(interfaceData)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - err = response.Body.Close() - if err != nil { - return err - } - - if response.StatusCode == http.StatusCreated { - return nil - } - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) -} diff --git a/inventory.go b/inventory.go new file mode 100644 index 0000000..86173bc --- /dev/null +++ b/inventory.go @@ -0,0 +1,108 @@ +package netboxgo + +import ( + "context" + "fmt" + "net/http" + "net/url" + + "github.com/gorilla/schema" +) + +type InventoryItemsService service + +type NewInventoryItem struct { + Device int `json:"device"` + Parent int `json:"parent"` + Name string `json:"name"` + Manufacturer int `json:"manufacturer"` + PartID string `json:"part_id"` + Serial string `json:"serial"` + AssetTag string `json:"asset_tag"` + Discovered bool `json:"discovered"` + Description string `json:"description"` + Tags []string `json:"tags"` +} + +type InventoryItems struct { + Count int `json:"count"` + Next string `json:"next"` + Previous string `json:"previous"` + Results []struct { + ID int `json:"id"` + Device struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + DisplayName string `json:"display_name"` + } `json:"device"` + Parent int `json:"parent"` + Name string `json:"name"` + Manufacturer struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + DevicetypeCount int `json:"devicetype_count"` + } `json:"manufacturer"` + PartID string `json:"part_id"` + Serial string `json:"serial"` + AssetTag string `json:"asset_tag"` + Discovered bool `json:"discovered"` + Description string `json:"description"` + Tags []string `json:"tags"` + } `json:"results"` +} + +type InventoryItemFilter struct { + Device string `schema:"device"` +} + +const inventoryItemsPath = "/dcim/inventory-items" + +// List inventory-items. InventoryItemFilter is used to list based on filter queries. +func (s *InventoryItemsService) List(ctx context.Context, f *InventoryItemFilter) (*InventoryItems, error) { + var inventoryitems InventoryItems + var query string + var req *http.Request + var err error + + encoder := schema.NewEncoder() + + form := url.Values{} + err = encoder.Encode(f, form) + if err != nil { + return &inventoryitems, err + } + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", inventoryItemsPath, query, nil) + if err != nil { + return &inventoryitems, err + } + + _, err = s.client.do(req, &inventoryitems) + if err != nil { + return &inventoryitems, err + } + + return &inventoryitems, nil +} + +// Create a inventory-item +func (s *InventoryItemsService) Create(ctx context.Context, c *NewInventoryItem) error { + var err error + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", inventoryItemsPath, "", c) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + _, err = s.client.do(req, nil) + if err != nil { + return fmt.Errorf("unable to do request: %w", err) + } + + return nil +} diff --git a/netbox.go b/netbox.go index 358a66b..a2b1da3 100644 --- a/netbox.go +++ b/netbox.go @@ -1,9 +1,14 @@ package netboxgo import ( + "bytes" + "context" "crypto/tls" "encoding/json" + "fmt" + "io" "io/ioutil" + "log" "net/http" "net/url" "strings" @@ -12,13 +17,89 @@ import ( "github.com/pkg/errors" ) -// NetBox settings struct -type NetBox struct { - RootURL string - Token string - SessionKey string - FetchMode string +type DCIM struct { + Devices *DevicesService + DeviceRoles *DeviceRolesService + DeviceTypes *DeviceTypesService + InventoryItems *InventoryItemsService + RearPorts *RearPortsService +} + +type Virtualization struct { + Clusters *ClustersService + VirtualMachines *VirtualMachinesService +} + +type IPAM struct { + VLANs *VLANsService + VRFs *VRFsService + Prefixes *PrefixesService +} + +type Secret struct { + Secrets *SecretsService +} + +type Tenancy struct { + Tenants *TenantsService + Sites *SitesService + SiteGroups *SiteGroupsService +} + +// Client struct is used to create a new NetBox endpoint +type Client struct { + DCIM *DCIM + Tenancy *Tenancy + IPAM *IPAM + Virtualization *Virtualization + Secret *Secret + + Tenants *TenantsService + Sites *SitesService + SiteGroups *SiteGroupsService + VirtualMachines *VirtualMachinesService + Clusters *ClustersService + VLANs *VLANsService + Secrets *SecretsService + InventoryItems *InventoryItemsService + Devices *DevicesService + DeviceRoles *DeviceRolesService + DeviceTypes *DeviceTypesService + Interfaces *InterfacesService + Prefixes *PrefixesService + VRFs *VRFsService + RearPorts *RearPortsService + + // baseURL is the URL used for the base URL of the API + baseURL *url.URL + + // httpClient is used for HTTP requests + httpClient *http.Client + + // Reuse a single struct instead of allocating one for each service on the heap. + common service + + // UserAgent is used to set the UserAgent on the HTTP requests + UserAgent string + + // Token is set for authentication of the API + Token string + + // Debug enables verbose debugging messages to console. + Debug bool + + // InsecureSkipVerify is used to selectively skip InsecureVerifications InsecureSkipVerify bool + + // SessionKey is used to read authentication data + SessionKey string + + // Used by golang wasm + FetchMode string +} + +type service struct { + client *Client } // NetBoxSessionKey sets the session key for secrets retrieval @@ -26,15 +107,79 @@ type NetBoxSessionKey struct { XSessionKey string `json:"session_key"` } -// New populates the NetBox settings struct -func (n *NetBox) New(root, token string, TLSSkipVerify bool) { - n.RootURL = root - n.Token = token - n.InsecureSkipVerify = TLSSkipVerify +// NewClient returns a new NetBox API client +func NewClient(apiurl string, httpClient *http.Client) (*Client, error) { + c := &Client{} + + api, err := url.Parse(apiurl) + if err != nil { + return c, fmt.Errorf("unable to parse url %s: %w", apiurl, err) + } + + c.baseURL = api + c.SetDebug(false) + c.SetUserAgent("netboxgo/0.0.6") + c.httpClient = httpClient + + if httpClient == nil { + transport := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, + CipherSuites: []uint16{ + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + }, + MinVersion: tls.VersionTLS12, + }, + Proxy: http.ProxyFromEnvironment, + } + + timeout := time.Duration(60 * time.Second) + c.httpClient = &http.Client{ + Transport: transport, + Jar: nil, + Timeout: timeout, + } + } + + c.common.client = c + c.Clusters = (*ClustersService)(&c.common) + c.Devices = (*DevicesService)(&c.common) + c.DeviceRoles = (*DeviceRolesService)(&c.common) + c.DeviceTypes = (*DeviceTypesService)(&c.common) + c.Interfaces = (*InterfacesService)(&c.common) + c.InventoryItems = (*InventoryItemsServices)(&c.common) + c.Prefixes = (*PrefixesService)(&c.common) + c.RearPorts = (*RearPortsService)(&c.common) + c.Tenants = (*TenantsService)(&c.common) + c.Secrets = (*SecretsService)(&c.common) + c.Sites = (*SitesService)(&c.common) + c.SiteGroups = (*SiteGroupsService)(&c.common) + c.VirtualMachines = (*VirtualMachinesService)(&c.common) + c.VLANs = (*VLANsService)(&c.common) + c.VRFs = (*VRFsService)(&c.common) + + return c, nil +} + +// SetUserAgent is used to set the user agent for interaction with the API +func (c *Client) SetUserAgent(u string) { + c.UserAgent = u +} + +// SetDebug is used to toggle debugging, set to true for debug +func (c *Client) SetDebug(b bool) { + c.Debug = b +} + +// SetToken is used to set the http token bearer for interaction with the API +func (c *Client) SetToken(token string) { + c.Token = token } // FetchSessionKey fetches sessionkey -func (n *NetBox) FetchSessionKey(privatekey string) error { +func (n *Client) FetchSessionKey(privatekey string) error { form := url.Values{} form.Add("private_key", privatekey) query := form.Encode() @@ -47,10 +192,12 @@ func (n *NetBox) FetchSessionKey(privatekey string) error { Timeout: timeout, Transport: transport, } - request, err := http.NewRequest("POST", n.RootURL+"/api/secrets/get-session-key/", strings.NewReader(query)) + const secretsPath = "/secrets" + request, err := http.NewRequest("POST", secretsPath+"/get-session-key/", strings.NewReader(query)) if err != nil { return err } + request.Header.Add("Accept", "application/json") request.Header.Add("Content-Type", "application/x-www-form-urlencoded") @@ -65,7 +212,7 @@ func (n *NetBox) FetchSessionKey(privatekey string) error { } if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n%s\n", response.StatusCode, http.StatusOK, response.Header) + return errors.Errorf("response was: %d should be %d\n%s\n", response.StatusCode, http.StatusOK, response.Header) } data, err := ioutil.ReadAll(response.Body) @@ -87,3 +234,96 @@ func (n *NetBox) FetchSessionKey(privatekey string) error { return nil } + +// newRequest is used to make new request to endpoints +func (c *Client) newRequest(ctx context.Context, method, path string, query string, body interface{}) (*http.Request, error) { + var err error + + var buf io.ReadWriter + + u := &url.URL{ + Scheme: c.baseURL.Scheme, + Host: c.baseURL.Host, + Path: c.baseURL.Path + path, + RawQuery: query, + } + + if body != nil { + buf = new(bytes.Buffer) + + err = json.NewEncoder(buf).Encode(body) + if err != nil { + return nil, err + } + } + + readBuf, _ := json.Marshal(body) + c.debugf("debug: method:%s url:%s body:%s", method, u.String(), string(readBuf)) + + req, err := http.NewRequestWithContext(ctx, method, u.String(), buf) + if err != nil { + return nil, err + } + + if body != nil { + req.Header.Set("Content-Type", "application/json") + } + + if c.SessionKey != "" { + req.Header.Add("X-Session-Key", c.SessionKey) + } + + req.Header.Set("Accept", "application/json") + if c.UserAgent != "" { + req.Header.Set("User-Agent", c.UserAgent) + } + + if c.Token != "" { + req.Header.Add("Authorization", "Bearer "+c.Token) + } + + if c.SessionKey != "" { + req.Header.Add("X-Session-Key", c.SessionKey) + } + + return req, nil +} + +// do method is used to decode request response to proper struct +func (c *Client) do(req *http.Request, v interface{}) (*http.Response, error) { + var err error + + var resp *http.Response + + resp, err = c.httpClient.Do(req) + if err != nil { + return nil, fmt.Errorf("client unable to do request: %w", err) + } + + if resp.StatusCode < 200 || resp.StatusCode > 299 { + var data []byte + + data, err = io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("unable to read body response: %w", err) + } + + return nil, fmt.Errorf("request failed: body=%s", string(data)) + } + + if v != nil { + err = json.NewDecoder(resp.Body).Decode(v) + if err != nil { + return resp, fmt.Errorf("unable to decode response body: %w", err) + } + } + + return resp, nil +} + +// debugf is used as a formtter for debugging information +func (c *Client) debugf(fmt string, v ...interface{}) { + if c.Debug { + log.Printf("cendot client: "+fmt, v...) + } +} diff --git a/netbox_inventory.go b/netbox_inventory.go deleted file mode 100644 index 73cc03a..0000000 --- a/netbox_inventory.go +++ /dev/null @@ -1,152 +0,0 @@ -package netboxgo - -import ( - "bytes" - "crypto/tls" - "encoding/json" - "io/ioutil" - "net/http" - "net/url" - "time" - - "github.com/gorilla/schema" - "github.com/pkg/errors" -) - -type AddInventory struct { - Device int `json:"device"` - Parent int `json:"parent"` - Name string `json:"name"` - Manufacturer int `json:"manufacturer"` - PartID string `json:"part_id"` - Serial string `json:"serial"` - AssetTag string `json:"asset_tag"` - Discovered bool `json:"discovered"` - Description string `json:"description"` - Tags []string `json:"tags"` -} - -type DcimInventoryItemsList struct { - Count int `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []struct { - ID int `json:"id"` - Device struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - DisplayName string `json:"display_name"` - } `json:"device"` - Parent int `json:"parent"` - Name string `json:"name"` - Manufacturer struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - DevicetypeCount int `json:"devicetype_count"` - } `json:"manufacturer"` - PartID string `json:"part_id"` - Serial string `json:"serial"` - AssetTag string `json:"asset_tag"` - Discovered bool `json:"discovered"` - Description string `json:"description"` - Tags []string `json:"tags"` - } `json:"results"` -} - -type InventoryFilter struct { - Device string `schema:"device"` -} - -// ListDevices method returns dcim_device_list from Netbox API -func (n *NetBox) ListInventory(d *DcimInventoryItemsList, f *InventoryFilter) error { - encoder := schema.NewEncoder() - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - deviceurl := n.RootURL + "/api/dcim/inventory-items/" - if f != nil { - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - deviceurl = deviceurl + "?" + query - } - var request *http.Request - var err error - request, err = http.NewRequest("GET", deviceurl, nil) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d (%s)\n", response.StatusCode, http.StatusOK, deviceurl) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &d) - if err != nil { - return err - } - return nil -} - -func (n *NetBox) AddInventory(v *AddInventory) error { - data, err := json.Marshal(v) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("POST", n.RootURL+"/api/dcim/inventory-items/", bytes.NewBuffer(data)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - err = response.Body.Close() - if err != nil { - return err - } - - if response.StatusCode == http.StatusCreated { - return nil - } - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) -} diff --git a/netbox_prefixes.go b/netbox_prefixes.go deleted file mode 100644 index 1549a43..0000000 --- a/netbox_prefixes.go +++ /dev/null @@ -1,217 +0,0 @@ -package netboxgo - -import ( - "bytes" - "crypto/tls" - "encoding/json" - - // "fmt" - "io/ioutil" - "net/http" - "net/url" - "time" - - "github.com/gorilla/schema" - "github.com/pkg/errors" -) - -// IpamPrefixesCreate is used for the return values from Netbox API ipam_prefixes_create -type IpamPrefixesCreate struct { - Prefix string `json:"prefix"` - Site int `json:"site"` - Vrf int `json:"vrf"` - Tenant int `json:"tenant"` - VLAN int `json:"vlan"` - Status int `json:"status"` - Role int `json:"role"` - IsPool bool `json:"is_pool"` - Description string `json:"description"` - Tags []string `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` -} - -// IpamPrefixesList is used for the return value from NetBox API ipam_prefixes_list -type IpamPrefixesList struct { - Count int `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []struct { - ID int `json:"id"` - Family struct { - Label string `json:"label"` - Value int `json:"value"` - } `json:"family"` - Prefix string `json:"prefix"` - Site struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"site"` - Vrf struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Rd string `json:"rd"` - PrefixCount int `json:"prefix_count"` - } `json:"vrf"` - Tenant struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"tenant"` - VLAN struct { - ID int `json:"id"` - URL string `json:"url"` - Vid int `json:"vid"` - Name string `json:"name"` - DisplayName string `json:"display_name"` - } `json:"vlan"` - Status struct { - Label string `json:"label"` - Value string `json:"value"` - } `json:"status"` - Role struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - PrefixCount int `json:"prefix_count"` - VLANCount int `json:"vlan_count"` - } `json:"role"` - IsPool bool `json:"is_pool"` - Description string `json:"description"` - Tags []struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - Color string `json:"color"` - } `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - } `json:"results"` -} - -// PrefixFilter is used to filter out returned object from Netbox API ipam_prefixes_list -type PrefixFilter struct { - Offset int64 `schema:"offset,omitempty"` - Limit int64 `schema:"limit,omitempty"` - - // User specific filters - Family string `schema:"family,omitempty"` - IsPool string `schema:"is_pool,omitempty"` - EnforceUnique string `schema:"enforce_unique,omitempty"` - TenantGroupID string `schema:"tenant_group_id,omitempty"` - TenantGroup string `schema:"tenant_group,omitempty"` - TenantID string `schema:"tenant_id,omitempty"` - Tenant string `schema:"tenant,omitempty"` - IDIn string `schema:"id__in,omitempty"` - Q string `schema:"q,omitempty"` - Tag string `schema:"tag,omitempty"` - Prefix string `schema:"prefix,omitempty"` - Within string `schema:"within,omitempty"` - WithinInclude string `schema:"within_include,omitempty"` - Contains string `schema:"contains,omitempty"` - MaskLength string `schema:"mask_length,omitempty"` - VrfID string `schema:"vrf_id,omitempty"` - Vrf string `schema:"vrf,omitempty"` - RegionID string `schema:"region_id,omitempty"` - Region string `schema:"region,omitempty"` - SiteID string `schema:"site_id,omitempty"` - Site string `schema:"site,omitempty"` - VLANID string `schema:"vlan_id,omitempty"` - Role string `schema:"role,omitempty"` - Status string `schema:"status,omitempty"` -} - -// ListPrefixes returns Netbox ipam_prefixes_list -func (n *NetBox) ListPrefixes(i *IpamPrefixesList, f *PrefixFilter) error { - encoder := schema.NewEncoder() - - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/ipam/prefixes/?"+query, nil) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil -} - -// CreatePrefixes creates interfaces via Netbox API ipam_prefixes_create -func (n *NetBox) CreatePrefixes(i *IpamPrefixesCreate) error { - vrfData, err := json.Marshal(i) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("POST", n.RootURL+"/api/ipam/prefixes/", bytes.NewBuffer(vrfData)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - err = response.Body.Close() - if err != nil { - return err - } - - if response.StatusCode == http.StatusCreated { - return nil - } - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) -} diff --git a/netbox_site_groups.go b/netbox_site_groups.go deleted file mode 100644 index 5b16497..0000000 --- a/netbox_site_groups.go +++ /dev/null @@ -1,157 +0,0 @@ -package netboxgo - -import ( - "crypto/tls" - "encoding/json" - - // "fmt" - "io/ioutil" - "net/http" - "net/url" - "time" - - "github.com/gorilla/schema" - "github.com/pkg/errors" -) - -type SiteGroupsList struct { - Count int `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []SiteGroupList `json:"results"` -} - -type SiteGroupList struct { - ID int `json:"id"` - URL string `json:"url"` - Display string `json:"display"` - Name string `json:"name"` - Slug string `json:"slug"` - Parent struct { - ID int `json:"id"` - URL string `json:"url"` - Display string `json:"display"` - Name string `json:"name"` - Slug string `json:"slug"` - SiteCount int `json:"site_count"` - Depth int `json:"_depth"` - } `json:"parent"` - Description string `json:"description"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - SiteCount int `json:"site_count"` - Depth int `json:"_depth"` -} - -// SiteFilter is used to filter out returned object from Netbox API tenancy_tenants_list -type SiteGroupFilter struct { - Offset int64 `schema:"offset,omitempty"` - Limit int64 `schema:"limit,omitempty"` - - // User specific filters - Name string `schema:"name,omitempty"` - ID string `schema:"id,omitempty"` - Slug string `schema:"slug,omitempty"` - Description string `schema:"description,omitempty"` - Group string `schema:"group,omitempty"` - GroupID string `schema:"group_id,omitempty"` - Parent string `schema:"parent,omitempty"` - IDIn string `schema:"id__in,omitempty"` - Q string `schema:"q,omitempty"` - Tag string `schema:"tag,omitempty"` -} - -// ListSitegroups returns Netbox tenancy_tenants_list -func (n *NetBox) ListSiteGroups(i *SiteGroupsList, f *SiteFilter) error { - encoder := schema.NewEncoder() - - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/dcim/sites/?"+query, nil) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil -} - -// GetSiteGroup returns a Netbox site-group -func (n *NetBox) GetSiteGroup(i *SiteGroupList, id string) error { - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/dcim/site-groups/"+id, nil) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil -} diff --git a/netbox_tenants.go b/netbox_tenants.go deleted file mode 100644 index 30d328b..0000000 --- a/netbox_tenants.go +++ /dev/null @@ -1,167 +0,0 @@ -package netboxgo - -import ( - "bytes" - "crypto/tls" - "encoding/json" - - // "fmt" - "io/ioutil" - "net/http" - "net/url" - "time" - - "github.com/gorilla/schema" - "github.com/pkg/errors" -) - -// TenancyTenantsCreate is used for the return values from Netbox API tenancy_tenants_create -type TenancyTenantsCreate struct { - Name string `json:"name"` - Slug string `json:"slug"` - Group int `json:"group"` - Description string `json:"description"` - Comments string `json:"comments"` - Tags []string `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` -} - -// TenancyTenantsList is used for the return value from NetBox API tenancy_tenants_list -type TenancyTenantsList struct { - Count int `json:"count"` - Next string `json:"next"` - Previous interface{} `json:"previous"` - Results []struct { - ID int `json:"id"` - Name string `json:"name"` - Slug string `json:"slug"` - Group struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"group"` - Description string `json:"description"` - Comments string `json:"comments"` - Tags []interface{} `json:"tags"` - CustomFields struct { - AccountNumber string `json:"account_number"` - AtlasCustNumber interface{} `json:"atlas_cust_number"` - TextField interface{} `json:"text_field"` - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - CircuitCount interface{} `json:"circuit_count"` - DeviceCount int `json:"device_count"` - IpaddressCount interface{} `json:"ipaddress_count"` - PrefixCount int `json:"prefix_count"` - RackCount interface{} `json:"rack_count"` - SiteCount int `json:"site_count"` - VirtualmachineCount interface{} `json:"virtualmachine_count"` - VlanCount int `json:"vlan_count"` - VrfCount interface{} `json:"vrf_count"` - } `json:"results"` -} - -// TenantFilter is used to filter out returned object from Netbox API tenancy_tenants_list -type TenantFilter struct { - Offset int64 `schema:"offset,omitempty"` - Limit int64 `schema:"limit,omitempty"` - - // User specific filters - Name string `schema:"name,omitempty"` - Slug string `schema:"slug,omitempty"` - Group string `schema:"group,omitempty"` - GroupID string `schema:"group_id,omitempty"` - IDIn string `schema:"id__in,omitempty"` - Q string `schema:"q,omitempty"` - Tag string `schema:"tag,omitempty"` -} - -// ListTenants returns Netbox tenancy_tenants_list -func (n *NetBox) ListTenants(i *TenancyTenantsList, f *TenantFilter) error { - encoder := schema.NewEncoder() - - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/tenancy/tenants/?"+query, nil) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil -} - -// CreateTenants creates interfaces via Netbox API tenancy_tenants_create -func (n *NetBox) CreateTenants(i *TenancyTenantsCreate) error { - vrfData, err := json.Marshal(i) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("POST", n.RootURL+"/api/tenancy/tenants/", bytes.NewBuffer(vrfData)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - err = response.Body.Close() - if err != nil { - return err - } - - if response.StatusCode == http.StatusCreated { - return nil - } - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) -} diff --git a/netbox_virtualization.go b/netbox_virtualization.go deleted file mode 100644 index 5d734f9..0000000 --- a/netbox_virtualization.go +++ /dev/null @@ -1,284 +0,0 @@ -package netboxgo - -import ( - "bytes" - "crypto/tls" - "encoding/json" - - "io/ioutil" - "net/http" - "net/url" - - "time" - - "github.com/gorilla/schema" - "github.com/pkg/errors" -) - -//VirtualizationVirtualMachinesCreate is used to create new VirtualizationVirtualMachines -type VirtualizationVirtualMachinesCreate struct { - ID int `json:"id"` - Name string `json:"name"` - Status struct { - Label string `json:"label"` - Value int `json:"value"` - } `json:"status"` - Site struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"site"` - Cluster struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - VirtualmachineCount int `json:"virtualmachine_count"` - } `json:"cluster"` - Role struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - DeviceCount int `json:"device_count"` - VirtualmachineCount int `json:"virtualmachine_count"` - } `json:"role"` - Tenant struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"tenant"` - Platform struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - DeviceCount int `json:"device_count"` - VirtualmachineCount int `json:"virtualmachine_count"` - } `json:"platform"` - PrimaryIP struct { - ID int `json:"id"` - URL string `json:"url"` - Family int `json:"family"` - Address string `json:"address"` - } `json:"primary_ip"` - PrimaryIP4 struct { - ID int `json:"id"` - URL string `json:"url"` - Family int `json:"family"` - Address string `json:"address"` - } `json:"primary_ip4"` - PrimaryIP6 struct { - ID int `json:"id"` - URL string `json:"url"` - Family int `json:"family"` - Address string `json:"address"` - } `json:"primary_ip6"` - Vcpus int `json:"vcpus"` - Memory int `json:"memory"` - Disk int `json:"disk"` - Comments string `json:"comments"` - LocalContextData string `json:"local_context_data"` - Tags []string `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` - ConfigContext struct { - AdditionalProp1 string `json:"additionalProp1"` - AdditionalProp2 string `json:"additionalProp2"` - AdditionalProp3 string `json:"additionalProp3"` - } `json:"config_context"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` -} - -//VirtualizationClustersCreate is used to create new VirtualizationClusters -type VirtualizationClustersCreate struct { - ID int `json:"id"` - Name string `json:"name"` - Type struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - ClusterCount int `json:"cluster_count"` - } `json:"type"` - Group struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - ClusterCount int `json:"cluster_count"` - } `json:"group"` - Site struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"site"` - Comments string `json:"comments"` - Tags []struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - Color string `json:"color"` - } `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - DeviceCount int `json:"device_count"` - VirtualmachineCount int `json:"virtualmachine_count"` -} - -// VirtualizationClustersList is used to list VirtualizationClusters -type VirtualizationClustersList struct { - Count int `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []struct { - ID int `json:"id"` - Name string `json:"name"` - Type struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - ClusterCount int `json:"cluster_count"` - } `json:"type"` - Group struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - ClusterCount int `json:"cluster_count"` - } `json:"group"` - Site struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"site"` - Comments string `json:"comments"` - Tags []struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - Color string `json:"color"` - } `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - DeviceCount int `json:"device_count"` - VirtualmachineCount int `json:"virtualmachine_count"` - } `json:"results"` -} - -// ClusterFilter is used to filter out VirtualizationClusters -type ClusterFilter struct { - Offset int64 `schema:"offset,omitempty"` - Limit int64 `schema:"limit,omitempty"` - - //User specific filters - Name string `schema:"name,omitempty"` - Group string `schema:"group,omitempty"` - GroupID string `schema:"group_id,omitempty"` - TypeID string `schema:"type_id,omitempty"` - Type string `schema:"type,omitempty"` - SiteID string `schema:"site_id,omitempty"` - Site string `schema:"site,omitempty"` - Tenant string `schema:"tenant,omitempty"` - IDIn string `schema:"id__in,omitempty"` - Q string `schema:"q,omitempty"` - Tag string `schema:"tag,omitempty"` -} - -// ListClusters returns Netbox virtualization_clusters -func (n *NetBox) ListClusters(i *VirtualizationClustersList, f *ClusterFilter) error { - var encoder = schema.NewEncoder() - - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/virtualization/clusters/?"+query, nil) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil -} - -// CreateVirtualMachine creates VirtualMachines via Netbox API dcim_interfaces_create -func (n *NetBox) CreateVirtualMachine(v *VirtualizationClustersCreate) error { - data, err := json.Marshal(v) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("POST", n.RootURL+"/api/virtualization/virtual-machines/", bytes.NewBuffer(data)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - err = response.Body.Close() - if err != nil { - return err - } - - if response.StatusCode == http.StatusCreated { - return nil - } - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) -} diff --git a/netbox_vlans.go b/netbox_vlans.go deleted file mode 100644 index 1431474..0000000 --- a/netbox_vlans.go +++ /dev/null @@ -1,240 +0,0 @@ -package netboxgo - -import ( - "bytes" - "crypto/tls" - "encoding/json" - - // "fmt" - "io/ioutil" - "net/http" - "net/url" - "time" - - "github.com/gorilla/schema" - "github.com/pkg/errors" -) - -// IpamVLANsCreate is used for the return values from Netbox API ipam_vlans_create -type IpamVLANsCreate struct { - Site int `json:"site"` - Group int `json:"group"` - Vid int `json:"vid"` - Name string `json:"name"` - Tenant int `json:"tenant"` - Status int `json:"status"` - Role int `json:"role"` - Description string `json:"description"` - Tags []string `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` -} - -type IpamVLAN struct { - ID int `json:"id"` - Site struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"site"` - Group struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - VLANCount int `json:"vlan_count"` - } `json:"group"` - Vid int `json:"vid"` - Name string `json:"name"` - Tenant struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"tenant"` - Status struct { - Label string `json:"label"` - Value string `json:"value"` - } `json:"status"` - Role struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - PrefixCount int `json:"prefix_count"` - VLANCount int `json:"vlan_count"` - } `json:"role"` - Description string `json:"description"` - Tags []string `json:"tags"` - DisplayName string `json:"display_name"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - PrefixCount int `json:"prefix_count"` -} - -// IpamVLANsList is used for the return value from NetBox API ipam_vlans_list -type IpamVLANsList struct { - Count int `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []IpamVLAN `json:"results"` -} - -type VLAN struct { - ID int `json:"id"` - Site struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"site"` - Group struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - VLANCount int `json:"vlan_count"` - } `json:"group"` - Vid int `json:"vid"` - Name string `json:"name"` - Tenant struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"tenant"` - Status struct { - Label string `json:"label"` - Value string `json:"value"` - } `json:"status"` - Role struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - PrefixCount int `json:"prefix_count"` - VLANCount int `json:"vlan_count"` - } `json:"role"` - Description string `json:"description"` - Tags []string `json:"tags"` - DisplayName string `json:"display_name"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - PrefixCount int `json:"prefix_count"` -} - -// VLANFilter is used to filter out returned object from Netbox API ipam_vlans_list -type VLANFilter struct { - Offset int64 `schema:"offset,omitempty"` - Limit int64 `schema:"limit,omitempty"` - - // User specific filters - Vid string `schema:"vid,omitempty"` - Name string `schema:"name,omitempty"` - TenantGroupID string `schema:"tenant_group_id,omitempty"` - TenantGroup string `schema:"tenant_group,omitempty"` - TenantID string `schema:"tenant_id,omitempty"` - Tenant string `schema:"tenant,omitempty"` - IDIn string `schema:"id__in,omitempty"` - Q string `schema:"q,omitempty"` - SiteID string `schema:"site_id,omitempty"` - Site string `schema:"site,omitempty"` - GroupID string `schema:"group_id,omitempty"` - Group string `schema:"group,omitempty"` - RoleID string `schema:"role_id,omitempty"` - Role string `schema:"role,omitempty"` - Status string `schema:"status,omitempty"` - Tag string `schema:"tag,omitempty"` -} - -// ListVLANs returns Netbox ipam_vlans_list -func (n *NetBox) ListVLANs(i *IpamVLANsList, f *VLANFilter) error { - encoder := schema.NewEncoder() - - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/ipam/vlans/?"+query, nil) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil -} - -// CreateVLANs creates interfaces via Netbox API ipam_vlans_create -func (n *NetBox) CreateVLANs(i *IpamVLANsCreate) error { - vrfData, err := json.Marshal(i) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("POST", n.RootURL+"/api/ipam/vlans/", bytes.NewBuffer(vrfData)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - err = response.Body.Close() - if err != nil { - return err - } - - if response.StatusCode == http.StatusCreated { - return nil - } - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) -} diff --git a/netbox_vrfs.go b/netbox_vrfs.go deleted file mode 100644 index 81270ba..0000000 --- a/netbox_vrfs.go +++ /dev/null @@ -1,161 +0,0 @@ -package netboxgo - -import ( - "bytes" - "crypto/tls" - "encoding/json" - - // "fmt" - "io/ioutil" - "net/http" - "net/url" - "time" - - "github.com/gorilla/schema" - "github.com/pkg/errors" -) - -// IpamVrfsCreate is used for the return values from Netbox API ipam_vrfs_create -type IpamVrfsCreate struct { - Name string `json:"name"` - Rd string `json:"rd"` - Tenant int `json:"tenant"` - EnforceUnique bool `json:"enforce_unique"` - Description string `json:"description"` - Tags []string `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` -} - -// IpamVrfsList is used for the return value from NetBox API ipam_vrfs_list -type IpamVrfsList struct { - Count int `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []struct { - ID int `json:"id"` - Name string `json:"name"` - Rd string `json:"rd"` - Tenant struct { - ID int `json:"id"` - URL string `json:"url"` - Name string `json:"name"` - Slug string `json:"slug"` - } `json:"tenant"` - EnforceUnique bool `json:"enforce_unique"` - Description string `json:"description"` - Tags []string `json:"tags"` - DisplayName string `json:"display_name"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` - IpaddressCount int `json:"ipaddress_count"` - PrefixCount int `json:"prefix_count"` - } `json:"results"` -} - -// VrfFilter is used to filter out returned object from Netbox API ipam_vrfs_list -type VrfFilter struct { - Offset int64 `schema:"offset,omitempty"` - Limit int64 `schema:"limit,omitempty"` - - //User specific filters - Name string `schema:"name,omitempty"` - RD string `schema:"rd,omitempty"` - EnforceUnique string `schema:"enforce_unique,omitempty"` - TenantGroupID string `schema:"tenant_group_id,omitempty"` - TenantGroup string `schema:"tenant_group,omitempty"` - TenantID string `schema:"tenant_id,omitempty"` - Tenant string `schema:"tenant,omitempty"` - IDIn string `schema:"id__in,omitempty"` - Q string `schema:"q,omitempty"` - Tag string `schema:"tag,omitempty"` -} - -// ListVrfs returns Netbox ipam_vrfs_list -func (n *NetBox) ListVrfs(i *IpamVrfsList, f *VrfFilter) error { - var encoder = schema.NewEncoder() - - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/ipam/vrfs/?"+query, nil) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil -} - -// CreateVrfs creates interfaces via Netbox API ipam_vrfs_create -func (n *NetBox) CreateVrfs(i *IpamVrfsCreate) error { - vrfData, err := json.Marshal(i) - if err != nil { - return err - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("POST", n.RootURL+"/api/ipam/vrfs/", bytes.NewBuffer(vrfData)) - if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - err = response.Body.Close() - if err != nil { - return err - } - - if response.StatusCode == http.StatusCreated { - return nil - } - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) -} diff --git a/prefixes.go b/prefixes.go new file mode 100644 index 0000000..23a9cad --- /dev/null +++ b/prefixes.go @@ -0,0 +1,282 @@ +package netboxgo + +import ( + "context" + "fmt" + "net/http" + "net/url" + "time" + + // "fmt" + + "github.com/gorilla/schema" +) + +type PrefixesService service + +// NewPrefix is used for the return values from Netbox API ipam_prefixes_create +type NewPrefix struct { + Prefix string `json:"prefix"` + Site int `json:"site"` + Vrf int `json:"vrf"` + Tenant int `json:"tenant"` + VLAN int `json:"vlan"` + Status int `json:"status"` + Role int `json:"role"` + IsPool bool `json:"is_pool"` + Description string `json:"description"` + Tags []string `json:"tags"` + CustomFields struct{} `json:"custom_fields"` +} + +// Prefixes is used for the return value from NetBox API ipam_prefixes_list +type Prefixes struct { + Count int `json:"count"` + Next string `json:"next"` + Previous string `json:"previous"` + Results []struct { + ID int `json:"id"` + Family struct { + Label string `json:"label"` + Value int `json:"value"` + } `json:"family"` + Prefix string `json:"prefix"` + Site struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"site"` + Vrf struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Rd string `json:"rd"` + PrefixCount int `json:"prefix_count"` + } `json:"vrf"` + Tenant struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"tenant"` + VLAN struct { + ID int `json:"id"` + URL string `json:"url"` + Vid int `json:"vid"` + Name string `json:"name"` + DisplayName string `json:"display_name"` + } `json:"vlan"` + Status struct { + Label string `json:"label"` + Value string `json:"value"` + } `json:"status"` + Role struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + PrefixCount int `json:"prefix_count"` + VLANCount int `json:"vlan_count"` + } `json:"role"` + IsPool bool `json:"is_pool"` + Description string `json:"description"` + Tags []struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + Color string `json:"color"` + } `json:"tags"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` + } `json:"results"` +} + +// PrefixFilter is used to filter out returned object from Netbox API ipam_prefixes_list +type PrefixFilter struct { + Offset int64 `schema:"offset,omitempty"` + Limit int64 `schema:"limit,omitempty"` + + // User specific filters + Family string `schema:"family,omitempty"` + IsPool string `schema:"is_pool,omitempty"` + EnforceUnique string `schema:"enforce_unique,omitempty"` + TenantGroupID string `schema:"tenant_group_id,omitempty"` + TenantGroup string `schema:"tenant_group,omitempty"` + TenantID string `schema:"tenant_id,omitempty"` + Tenant string `schema:"tenant,omitempty"` + IDIn string `schema:"id__in,omitempty"` + Q string `schema:"q,omitempty"` + Tag string `schema:"tag,omitempty"` + Prefix string `schema:"prefix,omitempty"` + Within string `schema:"within,omitempty"` + WithinInclude string `schema:"within_include,omitempty"` + Contains string `schema:"contains,omitempty"` + MaskLength string `schema:"mask_length,omitempty"` + VrfID string `schema:"vrf_id,omitempty"` + Vrf string `schema:"vrf,omitempty"` + RegionID string `schema:"region_id,omitempty"` + Region string `schema:"region,omitempty"` + SiteID string `schema:"site_id,omitempty"` + Site string `schema:"site,omitempty"` + VLANID string `schema:"vlan_id,omitempty"` + Role string `schema:"role,omitempty"` + Status string `schema:"status,omitempty"` +} + +const prefixesPath = "/ipam/prefixes" + +// List prefixes. PrefixFilter is used to list based on filter queries. +func (s *PrefixesService) List(ctx context.Context, f *PrefixFilter) (*Prefixes, error) { + var prefixes Prefixes + var query string + var req *http.Request + var err error + + encoder := schema.NewEncoder() + + form := url.Values{} + err = encoder.Encode(f, form) + if err != nil { + return &prefixes, err + } + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", prefixesPath, query, nil) + if err != nil { + return &prefixes, err + } + + _, err = s.client.do(req, &prefixes) + if err != nil { + return &prefixes, err + } + + return &prefixes, nil +} + +// Create a prefix +func (s *PrefixesService) Create(ctx context.Context, c *NewPrefix) error { + var err error + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", prefixesPath, "", c) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + _, err = s.client.do(req, nil) + if err != nil { + return fmt.Errorf("unable to do request: %w", err) + } + + return nil +} + +// // Update a prefix +// func (s *PrefixesService) Update(ctx context.Context, id string, c *UpdatePrefix) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", prefixesPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } +// // ListPrefixes returns Netbox ipam_prefixes_list +// func (n *NetBox) ListPrefixes(i *Prefixes, f *PrefixFilter) error { +// encoder := schema.NewEncoder() + +// form := url.Values{} +// err := encoder.Encode(f, form) +// if err != nil { +// return err +// } +// query := form.Encode() + +// transport := &http.Transport{ +// TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, +// } +// timeout := time.Duration(60 * time.Second) +// client := &http.Client{ +// Timeout: timeout, +// Transport: transport, +// } +// request, err := http.NewRequest("GET", n.RootURL+"/api/ipam/prefixes/?"+query, nil) +// if err != nil { +// return err +// } +// request.Header.Add("Accept", "application/json") +// request.Header.Add("Authorization", " Token "+n.Token) +// response, err := client.Do(request) +// if err != nil { +// return err +// } + +// if response.StatusCode != http.StatusOK { +// return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) +// } + +// data, err := ioutil.ReadAll(response.Body) +// if err != nil { +// return err +// } + +// err = response.Body.Close() +// if err != nil { +// return err +// } + +// err = json.Unmarshal(data, &i) +// if err != nil { +// return err +// } +// return nil +// } + +// // CreatePrefixes creates interfaces via Netbox API ipam_prefixes_create +// func (n *NetBox) CreatePrefixes(i *NewPrefix) error { +// vrfData, err := json.Marshal(i) +// if err != nil { +// return err +// } +// transport := &http.Transport{ +// TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, +// } +// timeout := time.Duration(60 * time.Second) +// client := &http.Client{ +// Timeout: timeout, +// Transport: transport, +// } +// request, err := http.NewRequest("POST", n.RootURL+"/api/ipam/prefixes/", bytes.NewBuffer(vrfData)) +// if err != nil { +// return err +// } +// request.Header.Add("Accept", "application/json") +// request.Header.Add("Content-Type", "application/json") +// request.Header.Add("Authorization", " Token "+n.Token) +// response, err := client.Do(request) +// if err != nil { +// return err +// } +// err = response.Body.Close() +// if err != nil { +// return err +// } + +// if response.StatusCode == http.StatusCreated { +// return nil +// } +// return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusCreated) +// } diff --git a/rear_ports.go b/rear_ports.go index fef1b03..e65b788 100644 --- a/rear_ports.go +++ b/rear_ports.go @@ -1,18 +1,16 @@ package netboxgo import ( - "crypto/tls" - "encoding/json" - "io/ioutil" + "context" "net/http" "net/url" - "time" "github.com/gorilla/schema" - "github.com/pkg/errors" ) -type RearPortList struct { +type RearPortsService service + +type RearPorts struct { Count int `json:"count"` Next string `json:"next"` Previous string `json:"previous"` @@ -54,58 +52,33 @@ type RearPortFilter struct { Device string `schema:"device,omitempty"` } -// ListRearPorts method returns dcim_device_list from Netbox API -func (n *NetBox) ListRearPorts(d *RearPortList, f *RearPortFilter) error { +const rearPortsPath = "/dcim/rear-ports" + +// List rearports. RearPortFilter is used to list based on filter queries. +func (s *RearPortsService) List(ctx context.Context, f *RearPortFilter) (*RearPorts, error) { + var rearports RearPorts + var query string + var req *http.Request + var err error + encoder := schema.NewEncoder() - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - deviceurl := n.RootURL + "/api/dcim/rear-ports/" - if f != nil { - form := url.Values{} - err := encoder.Encode(f, form) - if err != nil { - return err - } - query := form.Encode() - deviceurl = deviceurl + "?" + query - } - var request *http.Request - var err error - request, err = http.NewRequest("GET", deviceurl, nil) + form := url.Values{} + err = encoder.Encode(f, form) if err != nil { - return err + return &rearports, err } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", rearPortsPath, query, nil) if err != nil { - return err + return &rearports, err } - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d (%s)\n", response.StatusCode, http.StatusOK, deviceurl) + _, err = s.client.do(req, &rearports) + if err != nil { + return &rearports, err } - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &d) - if err != nil { - return err - } - return nil + return &rearports, nil } diff --git a/netbox_secrets.go b/secrets.go similarity index 55% rename from netbox_secrets.go rename to secrets.go index 5f974b8..583fbe3 100644 --- a/netbox_secrets.go +++ b/secrets.go @@ -1,19 +1,19 @@ package netboxgo import ( - "crypto/tls" - "encoding/json" - "io/ioutil" + "context" + "fmt" "net/http" "net/url" "time" "github.com/gorilla/schema" - "github.com/pkg/errors" ) -// SecretsList contains secrets -type SecretsList struct { +type SecretsService service + +// Secrets contains secrets +type Secrets struct { Count int `json:"count"` Next string `json:"next"` Previous string `json:"previous"` @@ -42,10 +42,9 @@ type SecretsList struct { Slug string `json:"slug"` Color string `json:"color"` } `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` } `json:"results"` } @@ -66,54 +65,40 @@ type SecretFilter struct { Tag string `schema:"tag,omitempty"` } -// ListSecrets returns Netbox Secrets -func (n *NetBox) ListSecrets(i *SecretsList, f *SecretFilter) error { +const secretsPath = "/secrets/secrets" + +// List secrets. SecretsFilter is used to list based on filter queries. +func (s *SecretsService) List(ctx context.Context, f *SecretFilter) (*Secrets, error) { + var secrets Secrets + var query string + var req *http.Request + var err error + + if s.client.SessionKey == "" { + return &secrets, fmt.Errorf("session key needed when interacting with secrets. no session key found: you need to fetch a session key with FetchSessionKey()") + } + encoder := schema.NewEncoder() form := url.Values{} - err := encoder.Encode(f, form) + err = encoder.Encode(f, form) if err != nil { - return err + return &secrets, err } - query := form.Encode() + query = form.Encode() - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/secrets/secrets/?"+query, nil) + req, err = s.client.newRequest(ctx, "GET", devicesPath, query, nil) if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - request.Header.Add("X-Session-Key", n.SessionKey) - response, err := client.Do(request) - if err != nil { - return err + return &secrets, err } - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) + _, err = s.client.do(req, &secrets) + if err != nil { + return &secrets, err } - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } + // Clean c.client.SessionKey from memory + s.client.SessionKey = "" - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil + return &secrets, nil } diff --git a/site_groups.go b/site_groups.go new file mode 100644 index 0000000..4db214b --- /dev/null +++ b/site_groups.go @@ -0,0 +1,151 @@ +package netboxgo + +import ( + "context" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/gorilla/schema" +) + +type SiteGroupsService service + +type SiteGroups struct { + Count int `json:"count"` + Next string `json:"next"` + Previous string `json:"previous"` + Results []SiteGroup `json:"results"` +} + +type SiteGroup struct { + ID int `json:"id"` + URL string `json:"url"` + Display string `json:"display"` + Name string `json:"name"` + Slug string `json:"slug"` + Parent struct { + ID int `json:"id"` + URL string `json:"url"` + Display string `json:"display"` + Name string `json:"name"` + Slug string `json:"slug"` + SiteCount int `json:"site_count"` + Depth int `json:"_depth"` + } `json:"parent"` + Description string `json:"description"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` + SiteCount int `json:"site_count"` + Depth int `json:"_depth"` +} + +// SiteFilter is used to filter out returned object from Netbox API tenancy_tenants_list +type SiteGroupFilter struct { + Offset int64 `schema:"offset,omitempty"` + Limit int64 `schema:"limit,omitempty"` + + // User specific filters + Name string `schema:"name,omitempty"` + ID string `schema:"id,omitempty"` + Slug string `schema:"slug,omitempty"` + Description string `schema:"description,omitempty"` + Group string `schema:"group,omitempty"` + GroupID string `schema:"group_id,omitempty"` + Parent string `schema:"parent,omitempty"` + IDIn string `schema:"id__in,omitempty"` + Q string `schema:"q,omitempty"` + Tag string `schema:"tag,omitempty"` +} + +const siteGroupsPath = "/dcim/site-groups" + +// List sitegroups. SiteGroupFilter is used to list based on filter queries. +func (s *SiteGroupsService) List(ctx context.Context, f *SiteGroupFilter) (*SiteGroups, error) { + var sitegroups SiteGroups + var query string + var req *http.Request + var err error + + encoder := schema.NewEncoder() + + form := url.Values{} + err = encoder.Encode(f, form) + if err != nil { + return &sitegroups, err + } + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", siteGroupsPath, query, nil) + if err != nil { + return &sitegroups, err + } + + _, err = s.client.do(req, &sitegroups) + if err != nil { + return &sitegroups, err + } + + return &sitegroups, nil +} + +// Create a sitegroup +// func (s *SiteGroupsService) Create(ctx context.Context, c *NewSiteGroup) error { +// var err error +// var req *http.Request +// +// req, err = s.client.newRequest(ctx, "POST", siteGroupsPath, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } +// +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } +// +// return nil +// } + +// Get a SiteGroup based on id +func (s *SiteGroupsService) Get(ctx context.Context, id string) (*SiteGroup, error) { + var sitegroup SiteGroup + + var err error + + path := fmt.Sprintf("%s/%s", siteGroupsPath, id) + + req, err := s.client.newRequest(ctx, "GET", path, "", nil) + if err != nil { + return &sitegroup, err + } + + _, err = s.client.do(req, &sitegroup) + if err != nil { + return &sitegroup, err + } + + return &sitegroup, err +} + +// // Update a device +// func (s *SiteGroupsService) Update(ctx context.Context, id string, c *UpdateDevice) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", siteGroupsPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } diff --git a/netbox_sites.go b/sites.go similarity index 56% rename from netbox_sites.go rename to sites.go index 033799d..fd747dd 100644 --- a/netbox_sites.go +++ b/sites.go @@ -1,27 +1,25 @@ package netboxgo import ( - "crypto/tls" - "encoding/json" - - // "fmt" - "io/ioutil" + "context" + "fmt" "net/http" "net/url" "time" "github.com/gorilla/schema" - "github.com/pkg/errors" ) -type SitesList struct { - Count int `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []SiteList `json:"results"` +type SitesService service + +type Sites struct { + Count int `json:"count"` + Next string `json:"next"` + Previous string `json:"previous"` + Results []Site `json:"results"` } -type SiteList struct { +type Site struct { ID int `json:"id"` URL string `json:"url"` Display string `json:"display"` @@ -76,8 +74,7 @@ type SiteList struct { Slug string `json:"slug"` Color string `json:"color"` } `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` + CustomFields struct{} `json:"custom_fields"` Created string `json:"created"` LastUpdated time.Time `json:"last_updated"` CircuitCount int `json:"circuit_count"` @@ -104,95 +101,92 @@ type SiteFilter struct { Tag string `schema:"tag,omitempty"` } -// ListTenants returns Netbox tenancy_tenants_list -func (n *NetBox) ListSites(i *SitesList, f *SiteFilter) error { +const sitesPath = "/dcim/sites" + +// List sites. SiteFilter is used to list based on filter queries. +func (s *SitesService) List(ctx context.Context, f *SiteFilter) (*Sites, error) { + var sites Sites + var query string + var req *http.Request + var err error + encoder := schema.NewEncoder() form := url.Values{} - err := encoder.Encode(f, form) + err = encoder.Encode(f, form) if err != nil { - return err + return &sites, err } - query := form.Encode() + query = form.Encode() - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/dcim/sites/?"+query, nil) + req, err = s.client.newRequest(ctx, "GET", sitesPath, query, nil) if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err + return &sites, err } - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) + _, err = s.client.do(req, &sites) + if err != nil { + return &sites, err } - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil + return &sites, nil } -// GetSite returns Netbox tenancy_tenants_list -func (n *NetBox) GetSite(i *SiteList, id string) error { - transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - request, err := http.NewRequest("GET", n.RootURL+"/api/dcim/sites/"+id, nil) +// Get a Site based on id +func (s *SitesService) Get(ctx context.Context, id string) (*Site, error) { + var site Site + + var err error + + path := fmt.Sprintf("%s/%s", sitesPath, id) + + req, err := s.client.newRequest(ctx, "GET", path, "", nil) if err != nil { - return err - } - request.Header.Add("Accept", "application/json") - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err + return &site, err } - if response.StatusCode != http.StatusOK { - return errors.Errorf("Error: response was: %d should be %d\n", response.StatusCode, http.StatusOK) + _, err = s.client.do(req, &site) + if err != nil { + return &site, err } - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } - - err = json.Unmarshal(data, &i) - if err != nil { - return err - } - return nil + return &site, err } + +// // Create a site +// func (s *SitesService) Create(ctx context.Context, c *NewSite) error { +// var err error +// var req *http.Request + +// req, err = s.client.newRequest(ctx, "POST", sitesPath, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } + +// // Update a device +// func (s *SitesService) Update(ctx context.Context, id string, c *UpdateDevice) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", sitesPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } diff --git a/tenants.go b/tenants.go new file mode 100644 index 0000000..76732ca --- /dev/null +++ b/tenants.go @@ -0,0 +1,145 @@ +package netboxgo + +import ( + "context" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/gorilla/schema" +) + +type TenantsService service + +// NewTenant is used for the return values from Netbox API tenancy_tenants_create +type NewTenant struct { + Name string `json:"name"` + Slug string `json:"slug"` + Group int `json:"group"` + Description string `json:"description"` + Comments string `json:"comments"` + Tags []string `json:"tags"` + CustomFields struct{} `json:"custom_fields"` +} + +// Tenants is used for the return value from NetBox API tenancy_tenants_list +type Tenants struct { + Count int `json:"count"` + Next string `json:"next"` + Previous interface{} `json:"previous"` + Results []struct { + ID int `json:"id"` + Name string `json:"name"` + Slug string `json:"slug"` + Group struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"group"` + Description string `json:"description"` + Comments string `json:"comments"` + Tags []interface{} `json:"tags"` + CustomFields struct { + AccountNumber string `json:"account_number"` + AtlasCustNumber interface{} `json:"atlas_cust_number"` + TextField interface{} `json:"text_field"` + } `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` + CircuitCount interface{} `json:"circuit_count"` + DeviceCount int `json:"device_count"` + IpaddressCount interface{} `json:"ipaddress_count"` + PrefixCount int `json:"prefix_count"` + RackCount interface{} `json:"rack_count"` + SiteCount int `json:"site_count"` + VirtualmachineCount interface{} `json:"virtualmachine_count"` + VlanCount int `json:"vlan_count"` + VrfCount interface{} `json:"vrf_count"` + } `json:"results"` +} + +// TenantFilter is used to filter out returned object from Netbox API tenancy_tenants_list +type TenantFilter struct { + Offset int64 `schema:"offset,omitempty"` + Limit int64 `schema:"limit,omitempty"` + + // User specific filters + Name string `schema:"name,omitempty"` + Slug string `schema:"slug,omitempty"` + Group string `schema:"group,omitempty"` + GroupID string `schema:"group_id,omitempty"` + IDIn string `schema:"id__in,omitempty"` + Q string `schema:"q,omitempty"` + Tag string `schema:"tag,omitempty"` +} + +const tenantsPath = "/tenancy/tenants" + +// List tenants. TenantFilter is used to list based on filter queries. +func (s *TenantsService) List(ctx context.Context, f *TenantFilter) (*Tenants, error) { + var tenants Tenants + var query string + var req *http.Request + var err error + + encoder := schema.NewEncoder() + + form := url.Values{} + err = encoder.Encode(f, form) + if err != nil { + return &tenants, err + } + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", tenantsPath, query, nil) + if err != nil { + return &tenants, err + } + + _, err = s.client.do(req, &tenants) + if err != nil { + return &tenants, err + } + + return &tenants, nil +} + +// Create a tenant +func (s *TenantsService) Create(ctx context.Context, c *NewTenant) error { + var err error + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", tenantsPath, "", c) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + _, err = s.client.do(req, nil) + if err != nil { + return fmt.Errorf("unable to do request: %w", err) + } + + return nil +} + +// // Update a device +// func (s *TenantsService) Update(ctx context.Context, id string, c *UpdateDevice) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", tenantsPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } diff --git a/virtual_machines.go b/virtual_machines.go new file mode 100644 index 0000000..83e5918 --- /dev/null +++ b/virtual_machines.go @@ -0,0 +1,106 @@ +package netboxgo + +import ( + "context" + "fmt" + "net/http" + "time" +) + +type VirtualMachinesService service + +// NewVirtualMachine is used to create new VirtualizationVirtualMachines +type NewVirtualMachine struct { + ID int `json:"id"` + Name string `json:"name"` + Status struct { + Label string `json:"label"` + Value int `json:"value"` + } `json:"status"` + Site struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"site"` + Cluster struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + VirtualmachineCount int `json:"virtualmachine_count"` + } `json:"cluster"` + Role struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + DeviceCount int `json:"device_count"` + VirtualmachineCount int `json:"virtualmachine_count"` + } `json:"role"` + Tenant struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"tenant"` + Platform struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + DeviceCount int `json:"device_count"` + VirtualmachineCount int `json:"virtualmachine_count"` + } `json:"platform"` + PrimaryIP struct { + ID int `json:"id"` + URL string `json:"url"` + Family int `json:"family"` + Address string `json:"address"` + } `json:"primary_ip"` + PrimaryIP4 struct { + ID int `json:"id"` + URL string `json:"url"` + Family int `json:"family"` + Address string `json:"address"` + } `json:"primary_ip4"` + PrimaryIP6 struct { + ID int `json:"id"` + URL string `json:"url"` + Family int `json:"family"` + Address string `json:"address"` + } `json:"primary_ip6"` + Vcpus int `json:"vcpus"` + Memory int `json:"memory"` + Disk int `json:"disk"` + Comments string `json:"comments"` + LocalContextData string `json:"local_context_data"` + Tags []string `json:"tags"` + CustomFields struct{} `json:"custom_fields"` + ConfigContext struct { + AdditionalProp1 string `json:"additionalProp1"` + AdditionalProp2 string `json:"additionalProp2"` + AdditionalProp3 string `json:"additionalProp3"` + } `json:"config_context"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` +} + +const virtualMachinesPath = "/virtualization/virtual-machines" + +// Create a virtual-machine +func (s *VirtualMachinesService) Create(ctx context.Context, c *NewVirtualMachine) error { + var err error + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", virtualMachinesPath, "", c) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + _, err = s.client.do(req, nil) + if err != nil { + return fmt.Errorf("unable to do request: %w", err) + } + + return nil +} diff --git a/vlans.go b/vlans.go new file mode 100644 index 0000000..1778bf4 --- /dev/null +++ b/vlans.go @@ -0,0 +1,172 @@ +package netboxgo + +import ( + "context" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/gorilla/schema" +) + +type VLANsService service + +// NewVLAN is used for the return values from Netbox API ipam_vlans_create +type NewVLAN struct { + Site int `json:"site"` + Group int `json:"group"` + Vid int `json:"vid"` + Name string `json:"name"` + Tenant int `json:"tenant"` + Status int `json:"status"` + Role int `json:"role"` + Description string `json:"description"` + Tags []string `json:"tags"` + CustomFields struct{} `json:"custom_fields"` +} + +type VLAN struct { + ID int `json:"id"` + Site struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"site"` + Group struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + VLANCount int `json:"vlan_count"` + } `json:"group"` + Vid int `json:"vid"` + Name string `json:"name"` + Tenant struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"tenant"` + Status struct { + Label string `json:"label"` + Value string `json:"value"` + } `json:"status"` + Role struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + PrefixCount int `json:"prefix_count"` + VLANCount int `json:"vlan_count"` + } `json:"role"` + Description string `json:"description"` + Tags []string `json:"tags"` + DisplayName string `json:"display_name"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` + PrefixCount int `json:"prefix_count"` +} + +// IpamVLANsList is used for the return value from NetBox API ipam_vlans_list +type VLANs struct { + Count int `json:"count"` + Next string `json:"next"` + Previous string `json:"previous"` + Results []VLAN `json:"results"` +} + +// VLANFilter is used to filter out returned object from Netbox API ipam_vlans_list +type VLANFilter struct { + Offset int64 `schema:"offset,omitempty"` + Limit int64 `schema:"limit,omitempty"` + + // User specific filters + Vid string `schema:"vid,omitempty"` + Name string `schema:"name,omitempty"` + TenantGroupID string `schema:"tenant_group_id,omitempty"` + TenantGroup string `schema:"tenant_group,omitempty"` + TenantID string `schema:"tenant_id,omitempty"` + Tenant string `schema:"tenant,omitempty"` + IDIn string `schema:"id__in,omitempty"` + Q string `schema:"q,omitempty"` + SiteID string `schema:"site_id,omitempty"` + Site string `schema:"site,omitempty"` + GroupID string `schema:"group_id,omitempty"` + Group string `schema:"group,omitempty"` + RoleID string `schema:"role_id,omitempty"` + Role string `schema:"role,omitempty"` + Status string `schema:"status,omitempty"` + Tag string `schema:"tag,omitempty"` +} + +const vlansPath = "/ipam/vlans" + +// List vlans. VLANFilter is used to list based on filter queries. +func (s *VLANsService) List(ctx context.Context, f *VLANFilter) (*VLANs, error) { + var vlans VLANs + var query string + var req *http.Request + var err error + + encoder := schema.NewEncoder() + + form := url.Values{} + err = encoder.Encode(f, form) + if err != nil { + return &vlans, err + } + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", vlansPath, query, nil) + if err != nil { + return &vlans, err + } + + _, err = s.client.do(req, &vlans) + if err != nil { + return &vlans, err + } + + return &vlans, nil +} + +// Create a device +func (s *VLANsService) Create(ctx context.Context, c *NewDevice) error { + var err error + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", vlansPath, "", c) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + _, err = s.client.do(req, nil) + if err != nil { + return fmt.Errorf("unable to do request: %w", err) + } + + return nil +} + +// // Update a device +// func (s *VLANsService) Update(ctx context.Context, id string, c *UpdateVLAN) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", vlansPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } diff --git a/vrfs.go b/vrfs.go new file mode 100644 index 0000000..c507ff8 --- /dev/null +++ b/vrfs.go @@ -0,0 +1,138 @@ +package netboxgo + +import ( + "context" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/gorilla/schema" +) + +type VRFsService service + +// NewVRF is used for the return values from Netbox API ipam_vrfs_create +type NewVRF struct { + Name string `json:"name"` + Rd string `json:"rd"` + Tenant int `json:"tenant"` + EnforceUnique bool `json:"enforce_unique"` + Description string `json:"description"` + Tags []string `json:"tags"` + CustomFields struct{} `json:"custom_fields"` +} + +// VRFs is used for the return value from NetBox API ipam_vrfs_list +type VRFs struct { + Count int `json:"count"` + Next string `json:"next"` + Previous string `json:"previous"` + Results []struct { + ID int `json:"id"` + Name string `json:"name"` + Rd string `json:"rd"` + Tenant struct { + ID int `json:"id"` + URL string `json:"url"` + Name string `json:"name"` + Slug string `json:"slug"` + } `json:"tenant"` + EnforceUnique bool `json:"enforce_unique"` + Description string `json:"description"` + Tags []string `json:"tags"` + DisplayName string `json:"display_name"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` + IpaddressCount int `json:"ipaddress_count"` + PrefixCount int `json:"prefix_count"` + } `json:"results"` +} + +// VRFFilter is used to filter out returned object from Netbox API ipam_vrfs_list +type VRFFilter struct { + Offset int64 `schema:"offset,omitempty"` + Limit int64 `schema:"limit,omitempty"` + + // User specific filters + Name string `schema:"name,omitempty"` + RD string `schema:"rd,omitempty"` + EnforceUnique string `schema:"enforce_unique,omitempty"` + TenantGroupID string `schema:"tenant_group_id,omitempty"` + TenantGroup string `schema:"tenant_group,omitempty"` + TenantID string `schema:"tenant_id,omitempty"` + Tenant string `schema:"tenant,omitempty"` + IDIn string `schema:"id__in,omitempty"` + Q string `schema:"q,omitempty"` + Tag string `schema:"tag,omitempty"` +} + +const vrfsPath = "/ipam/vrfs" + +// List vrfs. VRFFilter is used to list based on filter queries. +func (s *VRFsService) List(ctx context.Context, f *VRFFilter) (*VRFs, error) { + var vrfs VRFs + var query string + var req *http.Request + var err error + + encoder := schema.NewEncoder() + + form := url.Values{} + err = encoder.Encode(f, form) + if err != nil { + return &vrfs, err + } + query = form.Encode() + + req, err = s.client.newRequest(ctx, "GET", vrfsPath, query, nil) + if err != nil { + return &vrfs, err + } + + _, err = s.client.do(req, &vrfs) + if err != nil { + return &vrfs, err + } + + return &vrfs, nil +} + +// Create a device +func (s *VRFsService) Create(ctx context.Context, c *NewVRF) error { + var err error + var req *http.Request + + req, err = s.client.newRequest(ctx, "POST", vrfsPath, "", c) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + _, err = s.client.do(req, nil) + if err != nil { + return fmt.Errorf("unable to do request: %w", err) + } + + return nil +} + +// // Update a device +// func (s *VRFsService) Update(ctx context.Context, id string, c *UpdateVRF) error { +// var req *http.Request +// var err error + +// path := fmt.Sprintf("%s/%s", vrfsPath, id) + +// req, err = s.client.newRequest(ctx, "PATCH", path, "", c) +// if err != nil { +// return fmt.Errorf("unable to create request: %w", err) +// } + +// _, err = s.client.do(req, nil) +// if err != nil { +// return fmt.Errorf("unable to do request: %w", err) +// } + +// return nil +// } From 7fb583bd4e16d28e39d3160304f7d12ae42bdfde Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Fri, 26 Nov 2021 11:15:19 +0100 Subject: [PATCH 02/15] use correct path --- .pre-commit-config.yaml | 18 ++++++++++++++++++ devices.go | 12 ++++++------ netbox.go | 3 ++- secrets.go | 2 +- 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..af12555 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,18 @@ +repos: +- repo: https://git.candidator.se/go/dev-tools/pre-commit-golang.git + rev: f898003d6bfc677c18ee10210eb663fa5394cfb5 + hooks: + - id: go-fmt + - id: go-vet + - id: go-staticcheck + - id: go-imports + - id: go-cyclo + args: [-over=100] + - id: revive + - id: gosec + - id: validate-toml + - id: no-go-testing + # - id: golangci-lint + - id: go-critic + - id: go-unit-tests + - id: go-build diff --git a/devices.go b/devices.go index 84f982e..6b7ed0e 100644 --- a/devices.go +++ b/devices.go @@ -171,11 +171,11 @@ type Device struct { } type NewDevice struct { - Name string `json:"name,omitempty,omitempty"` - DeviceType int `json:"device_type,omitempty,omitempty"` - DeviceRole int `json:"device_role,omitempty,omitempty"` - Tenant int `json:"tenant,omitempty,omitempty"` - Platform int `json:"platform,omitempty,omitempty"` + Name string `json:"name,omitempty"` + DeviceType int `json:"device_type,omitempty"` + DeviceRole int `json:"device_role,omitempty"` + Tenant int `json:"tenant,omitempty"` + Platform int `json:"platform,omitempty"` Serial string `json:"serial,omitempty"` AssetTag string `json:"asset_tag,omitempty"` Site int `json:"site,omitempty"` @@ -257,7 +257,7 @@ type UpdateDevice struct { DcimDeviceBelongsToService int `json:"dcim_device_belongs_to_service,omitempty"` DcimDeviceCendotid string `json:"dcim_device_cendotid,omitempty"` DcimDeviceExposedToInternet int `json:"dcim_device_exposed_to_internet,omitempty"` - DcimDeviceImportOsVersion bool `json:"dcim_device_import_os_version,omitempty,omitempty"` + DcimDeviceImportOsVersion bool `json:"dcim_device_import_os_version,omitempty"` DcimDevicePod int `json:"dcim_device_pod,omitempty"` } `json:"custom_fields,omitempty"` } diff --git a/netbox.go b/netbox.go index a2b1da3..a880170 100644 --- a/netbox.go +++ b/netbox.go @@ -149,7 +149,7 @@ func NewClient(apiurl string, httpClient *http.Client) (*Client, error) { c.DeviceRoles = (*DeviceRolesService)(&c.common) c.DeviceTypes = (*DeviceTypesService)(&c.common) c.Interfaces = (*InterfacesService)(&c.common) - c.InventoryItems = (*InventoryItemsServices)(&c.common) + c.InventoryItems = (*InventoryItemsService)(&c.common) c.Prefixes = (*PrefixesService)(&c.common) c.RearPorts = (*RearPortsService)(&c.common) c.Tenants = (*TenantsService)(&c.common) @@ -185,6 +185,7 @@ func (n *Client) FetchSessionKey(privatekey string) error { query := form.Encode() transport := &http.Transport{ + // #nosec XXX: FIXIT TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, } timeout := time.Duration(60 * time.Second) diff --git a/secrets.go b/secrets.go index 583fbe3..08534c0 100644 --- a/secrets.go +++ b/secrets.go @@ -87,7 +87,7 @@ func (s *SecretsService) List(ctx context.Context, f *SecretFilter) (*Secrets, e } query = form.Encode() - req, err = s.client.newRequest(ctx, "GET", devicesPath, query, nil) + req, err = s.client.newRequest(ctx, "GET", secretsPath, query, nil) if err != nil { return &secrets, err } From 375dc521dc2cad76f91f48312ceff61ed0cd6af9 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Fri, 26 Nov 2021 11:16:54 +0100 Subject: [PATCH 03/15] do not include pre-commit in repo. --- .gitignore | 1 + .pre-commit-config.yaml | 18 ------------------ 2 files changed, 1 insertion(+), 18 deletions(-) create mode 100644 .gitignore delete mode 100644 .pre-commit-config.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e90b739 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index af12555..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -repos: -- repo: https://git.candidator.se/go/dev-tools/pre-commit-golang.git - rev: f898003d6bfc677c18ee10210eb663fa5394cfb5 - hooks: - - id: go-fmt - - id: go-vet - - id: go-staticcheck - - id: go-imports - - id: go-cyclo - args: [-over=100] - - id: revive - - id: gosec - - id: validate-toml - - id: no-go-testing - # - id: golangci-lint - - id: go-critic - - id: go-unit-tests - - id: go-build From c578285a054f67c814bf1846071b153d6d2d01e5 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Fri, 26 Nov 2021 13:21:19 +0100 Subject: [PATCH 04/15] Initialize service structs * DCIM * Tenancy * IPAM * Virtualization * Secret --- netbox.go | 73 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/netbox.go b/netbox.go index a880170..39b5836 100644 --- a/netbox.go +++ b/netbox.go @@ -21,6 +21,7 @@ type DCIM struct { Devices *DevicesService DeviceRoles *DeviceRolesService DeviceTypes *DeviceTypesService + Interfaces *InterfacesService InventoryItems *InventoryItemsService RearPorts *RearPortsService } @@ -54,21 +55,21 @@ type Client struct { Virtualization *Virtualization Secret *Secret - Tenants *TenantsService - Sites *SitesService - SiteGroups *SiteGroupsService - VirtualMachines *VirtualMachinesService - Clusters *ClustersService - VLANs *VLANsService - Secrets *SecretsService - InventoryItems *InventoryItemsService - Devices *DevicesService - DeviceRoles *DeviceRolesService - DeviceTypes *DeviceTypesService - Interfaces *InterfacesService - Prefixes *PrefixesService - VRFs *VRFsService - RearPorts *RearPortsService + // Tenants *TenantsService + // Sites *SitesService + // SiteGroups *SiteGroupsService + // VirtualMachines *VirtualMachinesService + // Clusters *ClustersService + // VLANs *VLANsService + // Secrets *SecretsService + // InventoryItems *InventoryItemsService + // Devices *DevicesService + // DeviceRoles *DeviceRolesService + // DeviceTypes *DeviceTypesService + // Interfaces *InterfacesService + // Prefixes *PrefixesService + // VRFs *VRFsService + // RearPorts *RearPortsService // baseURL is the URL used for the base URL of the API baseURL *url.URL @@ -85,17 +86,17 @@ type Client struct { // Token is set for authentication of the API Token string - // Debug enables verbose debugging messages to console. - Debug bool - - // InsecureSkipVerify is used to selectively skip InsecureVerifications - InsecureSkipVerify bool - // SessionKey is used to read authentication data SessionKey string // Used by golang wasm FetchMode string + + // Debug enables verbose debugging messages to console. + Debug bool + + // InsecureSkipVerify is used to selectively skip InsecureVerifications + InsecureSkipVerify bool } type service struct { @@ -144,21 +145,21 @@ func NewClient(apiurl string, httpClient *http.Client) (*Client, error) { } c.common.client = c - c.Clusters = (*ClustersService)(&c.common) - c.Devices = (*DevicesService)(&c.common) - c.DeviceRoles = (*DeviceRolesService)(&c.common) - c.DeviceTypes = (*DeviceTypesService)(&c.common) - c.Interfaces = (*InterfacesService)(&c.common) - c.InventoryItems = (*InventoryItemsService)(&c.common) - c.Prefixes = (*PrefixesService)(&c.common) - c.RearPorts = (*RearPortsService)(&c.common) - c.Tenants = (*TenantsService)(&c.common) - c.Secrets = (*SecretsService)(&c.common) - c.Sites = (*SitesService)(&c.common) - c.SiteGroups = (*SiteGroupsService)(&c.common) - c.VirtualMachines = (*VirtualMachinesService)(&c.common) - c.VLANs = (*VLANsService)(&c.common) - c.VRFs = (*VRFsService)(&c.common) + c.Virtualization.Clusters = (*ClustersService)(&c.common) + c.DCIM.Devices = (*DevicesService)(&c.common) + c.DCIM.DeviceRoles = (*DeviceRolesService)(&c.common) + c.DCIM.DeviceTypes = (*DeviceTypesService)(&c.common) + c.DCIM.Interfaces = (*InterfacesService)(&c.common) + c.DCIM.InventoryItems = (*InventoryItemsService)(&c.common) + c.IPAM.Prefixes = (*PrefixesService)(&c.common) + c.DCIM.RearPorts = (*RearPortsService)(&c.common) + c.Tenancy.Tenants = (*TenantsService)(&c.common) + c.Secret.Secrets = (*SecretsService)(&c.common) + c.Tenancy.Sites = (*SitesService)(&c.common) + c.Tenancy.SiteGroups = (*SiteGroupsService)(&c.common) + c.Virtualization.VirtualMachines = (*VirtualMachinesService)(&c.common) + c.IPAM.VLANs = (*VLANsService)(&c.common) + c.IPAM.VRFs = (*VRFsService)(&c.common) return c, nil } From 2be4afbbfd3f202139e1878fe59119a2fb0609e9 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Fri, 26 Nov 2021 13:24:09 +0100 Subject: [PATCH 05/15] Bump go version and fix relocation. --- go.mod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index fb6858d..fb2938b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ -module git.kcbark.net/kcbark/netboxgo +module git.kcbark.net/kc/netboxgo -go 1.15 +go 1.17 require ( github.com/gorilla/schema v1.1.0 From eb8f761cbc58b663c93a571d919178fe4c7a7190 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Fri, 26 Nov 2021 13:34:15 +0100 Subject: [PATCH 06/15] Revert categorized services. --- netbox.go | 70 +++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/netbox.go b/netbox.go index 39b5836..813a3ba 100644 --- a/netbox.go +++ b/netbox.go @@ -49,27 +49,27 @@ type Tenancy struct { // Client struct is used to create a new NetBox endpoint type Client struct { - DCIM *DCIM - Tenancy *Tenancy - IPAM *IPAM - Virtualization *Virtualization - Secret *Secret + // DCIM *DCIM + // Tenancy *Tenancy + // IPAM *IPAM + // Virtualization *Virtualization + // Secret *Secret - // Tenants *TenantsService - // Sites *SitesService - // SiteGroups *SiteGroupsService - // VirtualMachines *VirtualMachinesService - // Clusters *ClustersService - // VLANs *VLANsService - // Secrets *SecretsService - // InventoryItems *InventoryItemsService - // Devices *DevicesService - // DeviceRoles *DeviceRolesService - // DeviceTypes *DeviceTypesService - // Interfaces *InterfacesService - // Prefixes *PrefixesService - // VRFs *VRFsService - // RearPorts *RearPortsService + Tenants *TenantsService + Sites *SitesService + SiteGroups *SiteGroupsService + VirtualMachines *VirtualMachinesService + Clusters *ClustersService + VLANs *VLANsService + Secrets *SecretsService + InventoryItems *InventoryItemsService + Devices *DevicesService + DeviceRoles *DeviceRolesService + DeviceTypes *DeviceTypesService + Interfaces *InterfacesService + Prefixes *PrefixesService + VRFs *VRFsService + RearPorts *RearPortsService // baseURL is the URL used for the base URL of the API baseURL *url.URL @@ -145,21 +145,21 @@ func NewClient(apiurl string, httpClient *http.Client) (*Client, error) { } c.common.client = c - c.Virtualization.Clusters = (*ClustersService)(&c.common) - c.DCIM.Devices = (*DevicesService)(&c.common) - c.DCIM.DeviceRoles = (*DeviceRolesService)(&c.common) - c.DCIM.DeviceTypes = (*DeviceTypesService)(&c.common) - c.DCIM.Interfaces = (*InterfacesService)(&c.common) - c.DCIM.InventoryItems = (*InventoryItemsService)(&c.common) - c.IPAM.Prefixes = (*PrefixesService)(&c.common) - c.DCIM.RearPorts = (*RearPortsService)(&c.common) - c.Tenancy.Tenants = (*TenantsService)(&c.common) - c.Secret.Secrets = (*SecretsService)(&c.common) - c.Tenancy.Sites = (*SitesService)(&c.common) - c.Tenancy.SiteGroups = (*SiteGroupsService)(&c.common) - c.Virtualization.VirtualMachines = (*VirtualMachinesService)(&c.common) - c.IPAM.VLANs = (*VLANsService)(&c.common) - c.IPAM.VRFs = (*VRFsService)(&c.common) + c.Clusters = (*ClustersService)(&c.common) + c.Devices = (*DevicesService)(&c.common) + c.DeviceRoles = (*DeviceRolesService)(&c.common) + c.DeviceTypes = (*DeviceTypesService)(&c.common) + c.Interfaces = (*InterfacesService)(&c.common) + c.InventoryItems = (*InventoryItemsService)(&c.common) + c.Prefixes = (*PrefixesService)(&c.common) + c.RearPorts = (*RearPortsService)(&c.common) + c.Tenants = (*TenantsService)(&c.common) + c.Secrets = (*SecretsService)(&c.common) + c.Sites = (*SitesService)(&c.common) + c.SiteGroups = (*SiteGroupsService)(&c.common) + c.VirtualMachines = (*VirtualMachinesService)(&c.common) + c.VLANs = (*VLANsService)(&c.common) + c.VRFs = (*VRFsService)(&c.common) return c, nil } From e23a54368edea5c5d49d49b9f170073fdbc840c6 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Fri, 26 Nov 2021 13:39:29 +0100 Subject: [PATCH 07/15] Add tls1.2 ciphers. --- netbox.go | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox.go b/netbox.go index 813a3ba..f2ba069 100644 --- a/netbox.go +++ b/netbox.go @@ -129,6 +129,7 @@ func NewClient(apiurl string, httpClient *http.Client) (*Client, error) { CipherSuites: []uint16{ tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_CHACHA20_POLY1305_SHA256, }, MinVersion: tls.VersionTLS12, From b054d32835f6ac305b690b805939e218ed48073c Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Sat, 27 Nov 2021 13:10:56 +0100 Subject: [PATCH 08/15] Add ability to set custom token prefix --- netbox.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/netbox.go b/netbox.go index f2ba069..7d79744 100644 --- a/netbox.go +++ b/netbox.go @@ -86,6 +86,9 @@ type Client struct { // Token is set for authentication of the API Token string + // TokenPrefix is optional to set token prefix other than "Token" + TokenPrefix string + // SessionKey is used to read authentication data SessionKey string @@ -282,7 +285,11 @@ func (c *Client) newRequest(ctx context.Context, method, path string, query stri } if c.Token != "" { - req.Header.Add("Authorization", "Bearer "+c.Token) + req.Header.Add("Authorization", "Token "+c.Token) + } + + if c.Token != "" && c.TokenPrefix != "" { + req.Header.Add("Authorization", c.TokenPrefix+" "+c.Token) } if c.SessionKey != "" { From 47dc0361123834e19b941d3ab8ec8bbd4ca0a7c6 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Sat, 27 Nov 2021 13:24:15 +0100 Subject: [PATCH 09/15] Fix FetchSessionKey --- netbox.go | 53 +++++++++++++++-------------------------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/netbox.go b/netbox.go index 7d79744..241aa26 100644 --- a/netbox.go +++ b/netbox.go @@ -7,7 +7,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "log" "net/http" "net/url" @@ -184,59 +183,37 @@ func (c *Client) SetToken(token string) { } // FetchSessionKey fetches sessionkey -func (n *Client) FetchSessionKey(privatekey string) error { +func (c *Client) FetchSessionKey(privatekey string) error { form := url.Values{} form.Add("private_key", privatekey) query := form.Encode() - transport := &http.Transport{ - // #nosec XXX: FIXIT - TLSClientConfig: &tls.Config{InsecureSkipVerify: n.InsecureSkipVerify}, - } - timeout := time.Duration(60 * time.Second) - client := &http.Client{ - Timeout: timeout, - Transport: transport, - } - const secretsPath = "/secrets" - request, err := http.NewRequest("POST", secretsPath+"/get-session-key/", strings.NewReader(query)) + ctx := context.Background() + req, err := c.newRequest(ctx, "POST", secretsPath+"/get-session-key/", "", strings.NewReader(query)) if err != nil { return err } - request.Header.Add("Accept", "application/json") - request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Accept", "application/json") + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - if n.FetchMode != "" { - request.Header.Add("js.fetch:mode", "no-cors") + if c.FetchMode != "" { + req.Header.Add("js.fetch:mode", "no-cors") } - request.Header.Add("Authorization", " Token "+n.Token) - response, err := client.Do(request) - if err != nil { - return err - } - - if response.StatusCode != http.StatusOK { - return errors.Errorf("response was: %d should be %d\n%s\n", response.StatusCode, http.StatusOK, response.Header) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return err - } - - err = response.Body.Close() - if err != nil { - return err - } + req.Header.Add("Authorization", " Token "+c.Token) var sessionkey NetBoxSessionKey - err = json.Unmarshal(data, &sessionkey) + res, err := c.do(req, sessionkey) if err != nil { return err } - n.SessionKey = sessionkey.XSessionKey + + if res.StatusCode != http.StatusOK { + return errors.Errorf("response was: %d should be %d\n%s\n", res.StatusCode, http.StatusOK, res.Header) + } + + c.SessionKey = sessionkey.XSessionKey return nil } From 03799c289d502857ab52c9a1e5ab11b044103ea5 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Sat, 27 Nov 2021 23:31:44 +0100 Subject: [PATCH 10/15] Fix wrong path for secret get-session-key --- circuits.go | 11 +++++------ clusters.go | 2 +- device_roles.go | 2 +- device_types.go | 2 +- devices.go | 2 +- interfaces.go | 2 +- inventory.go | 2 +- netbox.go | 10 ++++++++++ prefixes.go | 2 +- rear_ports.go | 2 +- secrets.go | 4 ++-- site_groups.go | 2 +- sites.go | 2 +- tenants.go | 2 +- virtual_machines.go | 2 +- vlans.go | 2 +- vrfs.go | 2 +- 17 files changed, 31 insertions(+), 22 deletions(-) diff --git a/circuits.go b/circuits.go index 4411387..4919660 100644 --- a/circuits.go +++ b/circuits.go @@ -96,11 +96,10 @@ type Circuits struct { UpstreamSpeed int `json:"upstream_speed"` XconnectID string `json:"xconnect_id"` } `json:"termination_z"` - Comments string `json:"comments"` - Tags []string `json:"tags"` - CustomFields struct { - } `json:"custom_fields"` - Created string `json:"created"` - LastUpdated time.Time `json:"last_updated"` + Comments string `json:"comments"` + Tags []string `json:"tags"` + CustomFields struct{} `json:"custom_fields"` + Created string `json:"created"` + LastUpdated time.Time `json:"last_updated"` } `json:"results"` } diff --git a/clusters.go b/clusters.go index 675859d..3f591dc 100644 --- a/clusters.go +++ b/clusters.go @@ -114,7 +114,7 @@ type ClusterFilter struct { Tag string `schema:"tag,omitempty"` } -const clustersPath = "/virtualization/clusters" +const clustersPath = virtualizationPath + "/clusters" // List clusters. ClusterFilter is used to list based on filter queries. func (s *ClustersService) List(ctx context.Context, f *ClusterFilter) (*Clusters, error) { diff --git a/device_roles.go b/device_roles.go index 7bb75c2..8e93041 100644 --- a/device_roles.go +++ b/device_roles.go @@ -43,7 +43,7 @@ type DeviceRoleFilter struct { Q string `schema:"q,omitempty"` } -const deviceRolesPath = "/dcim/device-roles" +const deviceRolesPath = dcimPath + "/device-roles" // List deviceroles. DeviceRoleFilter is used to list based on filter queries. func (s *DeviceRolesService) List(ctx context.Context, f *DeviceRoleFilter) (*DeviceRoles, error) { diff --git a/device_types.go b/device_types.go index 2a3f2ca..b903389 100644 --- a/device_types.go +++ b/device_types.go @@ -70,7 +70,7 @@ type DeviceTypeFilter struct { Tag string `schema:"tag,omitempty"` } -const deviceTypesPath = "/dcim/device-types" +const deviceTypesPath = dcimPath + "/device-types" // List device-types. DeviceTypeFilter is used to list based on filter queries. func (s *DeviceTypesService) List(ctx context.Context, f *DeviceTypeFilter) (*DeviceTypes, error) { diff --git a/devices.go b/devices.go index 6b7ed0e..efb1fca 100644 --- a/devices.go +++ b/devices.go @@ -310,7 +310,7 @@ type DeviceFilter struct { Tag string `schema:"tag,omitempty"` } -const devicesPath = "/dcim/devices" +const devicesPath = dcimPath + "/devices" // List devices. DeviceFilter is used to list based on filter queries. func (s *DevicesService) List(ctx context.Context, f *DeviceFilter) (*Devices, error) { diff --git a/interfaces.go b/interfaces.go index 2be934e..c29f434 100644 --- a/interfaces.go +++ b/interfaces.go @@ -112,7 +112,7 @@ type InterfaceFilter struct { VLAN string `schema:"vlan,omitempty"` } -const interfacesPath = "/dcim/interfaces" +const interfacesPath = dcimPath + "/interfaces" // List devices. DeviceFilter is used to list based on filter queries. func (s *InterfacesService) List(ctx context.Context, f *InterfaceFilter) (*Interfaces, error) { diff --git a/inventory.go b/inventory.go index 86173bc..178fca2 100644 --- a/inventory.go +++ b/inventory.go @@ -58,7 +58,7 @@ type InventoryItemFilter struct { Device string `schema:"device"` } -const inventoryItemsPath = "/dcim/inventory-items" +const inventoryItemsPath = dcimPath + "/inventory-items" // List inventory-items. InventoryItemFilter is used to list based on filter queries. func (s *InventoryItemsService) List(ctx context.Context, f *InventoryItemFilter) (*InventoryItems, error) { diff --git a/netbox.go b/netbox.go index 241aa26..8a10a33 100644 --- a/netbox.go +++ b/netbox.go @@ -105,6 +105,16 @@ type service struct { client *Client } +const ( + circuitsPath = "/circuits" + dcimPath = "/dcim" + extrasPath = "/extras" + ipamPath = "/ipam" + tenancyPath = "/tenancy" + usersPath = "/users" + virtualizationPath = "/virtualization" +) + // NetBoxSessionKey sets the session key for secrets retrieval type NetBoxSessionKey struct { XSessionKey string `json:"session_key"` diff --git a/prefixes.go b/prefixes.go index 23a9cad..ee77658 100644 --- a/prefixes.go +++ b/prefixes.go @@ -126,7 +126,7 @@ type PrefixFilter struct { Status string `schema:"status,omitempty"` } -const prefixesPath = "/ipam/prefixes" +const prefixesPath = ipamPath + "/prefixes" // List prefixes. PrefixFilter is used to list based on filter queries. func (s *PrefixesService) List(ctx context.Context, f *PrefixFilter) (*Prefixes, error) { diff --git a/rear_ports.go b/rear_ports.go index e65b788..eeff745 100644 --- a/rear_ports.go +++ b/rear_ports.go @@ -52,7 +52,7 @@ type RearPortFilter struct { Device string `schema:"device,omitempty"` } -const rearPortsPath = "/dcim/rear-ports" +const rearPortsPath = dcimPath + "/rear-ports" // List rearports. RearPortFilter is used to list based on filter queries. func (s *RearPortsService) List(ctx context.Context, f *RearPortFilter) (*RearPorts, error) { diff --git a/secrets.go b/secrets.go index 08534c0..96f9913 100644 --- a/secrets.go +++ b/secrets.go @@ -65,7 +65,7 @@ type SecretFilter struct { Tag string `schema:"tag,omitempty"` } -const secretsPath = "/secrets/secrets" +const secretsPath = "/secrets" // List secrets. SecretsFilter is used to list based on filter queries. func (s *SecretsService) List(ctx context.Context, f *SecretFilter) (*Secrets, error) { @@ -87,7 +87,7 @@ func (s *SecretsService) List(ctx context.Context, f *SecretFilter) (*Secrets, e } query = form.Encode() - req, err = s.client.newRequest(ctx, "GET", secretsPath, query, nil) + req, err = s.client.newRequest(ctx, "GET", secretsPath+"/secrets", query, nil) if err != nil { return &secrets, err } diff --git a/site_groups.go b/site_groups.go index 4db214b..d59fd57 100644 --- a/site_groups.go +++ b/site_groups.go @@ -60,7 +60,7 @@ type SiteGroupFilter struct { Tag string `schema:"tag,omitempty"` } -const siteGroupsPath = "/dcim/site-groups" +const siteGroupsPath = dcimPath + "/site-groups" // List sitegroups. SiteGroupFilter is used to list based on filter queries. func (s *SiteGroupsService) List(ctx context.Context, f *SiteGroupFilter) (*SiteGroups, error) { diff --git a/sites.go b/sites.go index fd747dd..7490e1b 100644 --- a/sites.go +++ b/sites.go @@ -101,7 +101,7 @@ type SiteFilter struct { Tag string `schema:"tag,omitempty"` } -const sitesPath = "/dcim/sites" +const sitesPath = dcimPath + "/sites" // List sites. SiteFilter is used to list based on filter queries. func (s *SitesService) List(ctx context.Context, f *SiteFilter) (*Sites, error) { diff --git a/tenants.go b/tenants.go index 76732ca..9663712 100644 --- a/tenants.go +++ b/tenants.go @@ -75,7 +75,7 @@ type TenantFilter struct { Tag string `schema:"tag,omitempty"` } -const tenantsPath = "/tenancy/tenants" +const tenantsPath = tenancyPath + "/tenants" // List tenants. TenantFilter is used to list based on filter queries. func (s *TenantsService) List(ctx context.Context, f *TenantFilter) (*Tenants, error) { diff --git a/virtual_machines.go b/virtual_machines.go index 83e5918..cda07af 100644 --- a/virtual_machines.go +++ b/virtual_machines.go @@ -85,7 +85,7 @@ type NewVirtualMachine struct { LastUpdated time.Time `json:"last_updated"` } -const virtualMachinesPath = "/virtualization/virtual-machines" +const virtualMachinesPath = virtualizationPath + "/virtual-machines" // Create a virtual-machine func (s *VirtualMachinesService) Create(ctx context.Context, c *NewVirtualMachine) error { diff --git a/vlans.go b/vlans.go index 1778bf4..991da26 100644 --- a/vlans.go +++ b/vlans.go @@ -102,7 +102,7 @@ type VLANFilter struct { Tag string `schema:"tag,omitempty"` } -const vlansPath = "/ipam/vlans" +const vlansPath = ipamPath + "/vlans" // List vlans. VLANFilter is used to list based on filter queries. func (s *VLANsService) List(ctx context.Context, f *VLANFilter) (*VLANs, error) { diff --git a/vrfs.go b/vrfs.go index c507ff8..de200c6 100644 --- a/vrfs.go +++ b/vrfs.go @@ -68,7 +68,7 @@ type VRFFilter struct { Tag string `schema:"tag,omitempty"` } -const vrfsPath = "/ipam/vrfs" +const vrfsPath = ipamPath + "/vrfs" // List vrfs. VRFFilter is used to list based on filter queries. func (s *VRFsService) List(ctx context.Context, f *VRFFilter) (*VRFs, error) { From 36ba50352a5d4443a880f85e7a322229d68a3ef8 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Sat, 27 Nov 2021 23:46:52 +0100 Subject: [PATCH 11/15] I should add tests.. :) --- netbox.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netbox.go b/netbox.go index 8a10a33..089056a 100644 --- a/netbox.go +++ b/netbox.go @@ -10,7 +10,6 @@ import ( "log" "net/http" "net/url" - "strings" "time" "github.com/pkg/errors" @@ -199,7 +198,7 @@ func (c *Client) FetchSessionKey(privatekey string) error { query := form.Encode() ctx := context.Background() - req, err := c.newRequest(ctx, "POST", secretsPath+"/get-session-key/", "", strings.NewReader(query)) + req, err := c.newRequest(ctx, "POST", secretsPath+"/get-session-key/", "", query) if err != nil { return err } From 72862609c5fad428fc13039feda0af3fa8bce263 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Sat, 27 Nov 2021 23:52:51 +0100 Subject: [PATCH 12/15] Use built in function for special FetchSessionKey --- netbox.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netbox.go b/netbox.go index 089056a..2aa59c5 100644 --- a/netbox.go +++ b/netbox.go @@ -10,6 +10,7 @@ import ( "log" "net/http" "net/url" + "strings" "time" "github.com/pkg/errors" @@ -198,7 +199,7 @@ func (c *Client) FetchSessionKey(privatekey string) error { query := form.Encode() ctx := context.Background() - req, err := c.newRequest(ctx, "POST", secretsPath+"/get-session-key/", "", query) + req, err := http.NewRequestWithContext(ctx, "POST", secretsPath+"/get-session-key/", strings.NewReader(query)) if err != nil { return err } @@ -213,6 +214,7 @@ func (c *Client) FetchSessionKey(privatekey string) error { req.Header.Add("Authorization", " Token "+c.Token) var sessionkey NetBoxSessionKey + res, err := c.do(req, sessionkey) if err != nil { return err From 744837b9c7dcf23dc37183d61cffa7cb798aa074 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Sat, 27 Nov 2021 23:57:14 +0100 Subject: [PATCH 13/15] Fix URL in new request in special FetchSessionKey --- netbox.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox.go b/netbox.go index 2aa59c5..c9a2eca 100644 --- a/netbox.go +++ b/netbox.go @@ -199,7 +199,7 @@ func (c *Client) FetchSessionKey(privatekey string) error { query := form.Encode() ctx := context.Background() - req, err := http.NewRequestWithContext(ctx, "POST", secretsPath+"/get-session-key/", strings.NewReader(query)) + req, err := http.NewRequestWithContext(ctx, "POST", c.baseURL.String()+secretsPath+"/get-session-key/", strings.NewReader(query)) if err != nil { return err } From a8316057ce65348ff5409e4b234075366a65b549 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Sun, 28 Nov 2021 00:00:18 +0100 Subject: [PATCH 14/15] Add forgotten & --- netbox.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox.go b/netbox.go index c9a2eca..1e9cd12 100644 --- a/netbox.go +++ b/netbox.go @@ -215,7 +215,7 @@ func (c *Client) FetchSessionKey(privatekey string) error { var sessionkey NetBoxSessionKey - res, err := c.do(req, sessionkey) + res, err := c.do(req, &sessionkey) if err != nil { return err } From 76df69388442350415497d9f22e8cc013965dbe5 Mon Sep 17 00:00:00 2001 From: Kalle Carlbark Date: Sun, 28 Nov 2021 00:04:52 +0100 Subject: [PATCH 15/15] Do not clear from memory for now --- secrets.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/secrets.go b/secrets.go index 96f9913..59bdc95 100644 --- a/secrets.go +++ b/secrets.go @@ -97,8 +97,5 @@ func (s *SecretsService) List(ctx context.Context, f *SecretFilter) (*Secrets, e return &secrets, err } - // Clean c.client.SessionKey from memory - s.client.SessionKey = "" - return &secrets, nil }