Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): add SNMP configuration #36

Merged
merged 1 commit into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ run:
skip-files:
- internal/model/openconfig/oc_path.go
- internal/model/openconfig/oc.go
- internal/model/ietf/ietf.go

# Invariable parameters #

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ run:
-X 'github.com/criteo/data-aggregation-api/internal/version.buildTime=$(BUILDDATE)'" \
./cmd/data-aggregation-api

update_openconfig:
./update_openconfig.sh
update_yang_models:
./update_yang_models.sh
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ You need to update the following part in the code:
4. add your convertor in `internal/convertors/...`

3. execute your convertor (`internal/convertors/device/device.go`):
- GenerateOpenconfig()
- Generateconfigs()
50 changes: 50 additions & 0 deletions internal/api/router/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,56 @@ func (m *Manager) getDeviceOpenConfig(w http.ResponseWriter, _ *http.Request, ps
_, _ = w.Write(cfg)
}

// getDeviceIETFConfig endpoint returns Ietf JSON for one or all devices.
func (m *Manager) getDeviceIETFConfig(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) {
w.Header().Set(contentType, applicationJSON)
hostname := ps.ByName(hostnameKey)
if ps.ByName(hostnameKey) == wildcard {
cfg, err := m.devices.GetAllDevicesIETFConfigJSON()
if err != nil {
log.Error().Err(err).Send()
w.WriteHeader(http.StatusInternalServerError)
return
}

_, _ = w.Write(cfg)
return
}

cfg, err := m.devices.GetDeviceIETFConfigJSON(hostname)
if err != nil {
log.Error().Err(err).Send()
w.WriteHeader(http.StatusInternalServerError)
return
}
_, _ = w.Write(cfg)
}

// getDeviceConfig endpoint returns Ietf & openconfig JSON for one or all devices.
func (m *Manager) getDeviceConfig(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) {
w.Header().Set(contentType, applicationJSON)
hostname := ps.ByName(hostnameKey)
if ps.ByName(hostnameKey) == wildcard {
cfg, err := m.devices.GetAllDevicesConfigJSON()
if err != nil {
log.Error().Err(err).Send()
w.WriteHeader(http.StatusInternalServerError)
return
}

_, _ = w.Write(cfg)
return
}

cfg, err := m.devices.GetDeviceConfigJSON(hostname)
if err != nil {
log.Error().Err(err).Send()
w.WriteHeader(http.StatusInternalServerError)
return
}
_, _ = w.Write(cfg)
}

// getLastReport returns the last or current report.
func (m *Manager) getLastReport(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
out, err := m.reports.GetLastJSON()
Expand Down
6 changes: 6 additions & 0 deletions internal/api/router/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type DevicesRepository interface {
IsAFKEnabledJSON(hostname string) ([]byte, error)
GetAllDevicesOpenConfigJSON() ([]byte, error)
GetDeviceOpenConfigJSON(hostname string) ([]byte, error)
GetAllDevicesIETFConfigJSON() ([]byte, error)
GetDeviceIETFConfigJSON(hostname string) ([]byte, error)
GetAllDevicesConfigJSON() ([]byte, error)
GetDeviceConfigJSON(hostname string) ([]byte, error)
}

type Manager struct {
Expand Down Expand Up @@ -56,6 +60,8 @@ func (m *Manager) ListenAndServe(ctx context.Context, address string, port int)
router.GET("/api/health", healthCheck)
router.GET("/v1/devices/:hostname/afk_enabled", withAuth.Wrap(m.getAFKEnabled))
router.GET("/v1/devices/:hostname/openconfig", withAuth.Wrap(m.getDeviceOpenConfig))
router.GET("/v1/devices/:hostname/ietfconfig", withAuth.Wrap(m.getDeviceIETFConfig))
router.GET("/v1/devices/:hostname/config", withAuth.Wrap(m.getDeviceConfig))
router.GET("/v1/report/last", withAuth.Wrap(m.getLastReport))
router.GET("/v1/report/last/complete", withAuth.Wrap(m.getLastCompleteReport))
router.GET("/v1/report/last/successful", withAuth.Wrap(m.getLastSuccessfulReport))
Expand Down
65 changes: 56 additions & 9 deletions internal/convertor/device/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import (

bgpconvertors "github.com/criteo/data-aggregation-api/internal/convertor/bgp"
rpconvertors "github.com/criteo/data-aggregation-api/internal/convertor/routingpolicy"
snmpconvertors "github.com/criteo/data-aggregation-api/internal/convertor/snmp"
"github.com/criteo/data-aggregation-api/internal/ingestor/repository"
"github.com/criteo/data-aggregation-api/internal/model/cmdb/bgp"
"github.com/criteo/data-aggregation-api/internal/model/cmdb/routingpolicy"
"github.com/criteo/data-aggregation-api/internal/model/cmdb/snmp"
"github.com/criteo/data-aggregation-api/internal/model/dcim"
"github.com/criteo/data-aggregation-api/internal/model/ietf"
"github.com/criteo/data-aggregation-api/internal/model/openconfig"
"github.com/openconfig/ygot/ygot"
"github.com/rs/zerolog/log"
Expand All @@ -22,15 +25,18 @@ const AFKEnabledTag = "afk-enabled"
var defaultInstance = "default"

type GeneratedConfig struct {
Openconfig *openconfig.Device
JSON string
IETF *ietf.Device
JSONIETF string
Openconfig *openconfig.Device
JSONOpenConfig string
}

type Device struct {
mutex *sync.Mutex
Dcim *dcim.NetworkDevice
Config *GeneratedConfig
BGPGlobalConfig *bgp.BGPGlobal
SNMP *snmp.SNMP
Sessions []*bgp.Session
PeerGroups []*bgp.PeerGroup
PrefixLists []*routingpolicy.PrefixList
Expand Down Expand Up @@ -92,12 +98,16 @@ func NewDevice(dcimInfo *dcim.NetworkDevice, devicesData *repository.AssetsPerDe
return nil, fmt.Errorf("no route-policies found for %s", dcimInfo.Hostname)
}

device.SNMP, ok = devicesData.SNMP[dcimInfo.Hostname]
if !ok {
cpaillet marked this conversation as resolved.
Show resolved Hide resolved
log.Warn().Msgf("no snmp found for %s", dcimInfo.Hostname)
}
return device, nil
}

// GenerateOpenconfig generate the OpenConfig data for the current device.
// Generateconfigs generate the Config (openconfig & ietf) data for the current device.
// The CMDB data must have been precomputed before running this method.
func (d *Device) GenerateOpenconfig() error {
func (d *Device) Generateconfigs() error {
d.mutex.Lock()
defer d.mutex.Unlock()

Expand Down Expand Up @@ -139,23 +149,60 @@ func (d *Device) GenerateOpenconfig() error {
Indent: " ",
},
)

if err != nil {
return fmt.Errorf("failed to transform an openconfig device specification (%s) into JSON using ygot: %w", d.Dcim.Hostname, err)
}

d.Config = &GeneratedConfig{
Openconfig: &config,
JSON: devJSON,
Openconfig: &config,
JSONOpenConfig: devJSON,
IETF: nil,
JSONIETF: "{}",
}

if d.SNMP == nil {
log.Warn().Msgf("%s don't have a Snmp configuration, skip IetfConfig", d.Dcim.Hostname)
} else {
IetfSystem := snmpconvertors.SNMPtoIETFfSystem(d.SNMP)
IetfSnmp := snmpconvertors.SNMPtoIETFsnmp(d.SNMP)

d.Config.IETF = &ietf.Device{
System: &IetfSystem,
Snmp: &IetfSnmp,
}

d.Config.JSONIETF, err = ygot.EmitJSON(
d.Config.IETF,
&ygot.EmitJSONConfig{
Format: ygot.RFC7951,
SkipValidation: false,
Indent: " ",
},
)
if err != nil {
return fmt.Errorf("failed to transform an ietf device specification (%s) into JSON using ygot: %w", d.Dcim.Hostname, err)
}
}
return nil
}

// GetCompactJSON returns OpenConfig result in not indented JSON format.
// GetCompactOpenconfigJSON returns OpenConfig result in not indented JSON format.
// Generated JSON is already indented by Ygot - currently there is no option to not indent the JSON.
func (d *Device) GetCompactJSON() ([]byte, error) {
func (d *Device) GetCompactOpenconfigJSON() ([]byte, error) {
out := bytes.NewBuffer(nil)
err := json.Compact(out, []byte(d.Config.JSONOpenConfig))
if err != nil {
return nil, err
}
return out.Bytes(), nil
}

// GetCompactIETFJSON returns IETF result in not indented JSON format.
// GetCompactIETFJSON JSON is already indented by Ygot - currently there is no option to not indent the JSON.
func (d *Device) GetCompactIETFJSON() ([]byte, error) {
out := bytes.NewBuffer(nil)
err := json.Compact(out, []byte(d.Config.JSON))
err := json.Compact(out, []byte(d.Config.JSONIETF))
if err != nil {
return nil, err
}
Expand Down
Loading
Loading