Skip to content

Commit

Permalink
Add feature to specify the allowed dhcp cidrs
Browse files Browse the repository at this point in the history
  • Loading branch information
majst01 committed Sep 4, 2023
1 parent 53380e1 commit dc1f71d
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 35 deletions.
7 changes: 1 addition & 6 deletions internal/leases/leases.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package leases

import (
"fmt"
"os"
"time"
)
Expand Down Expand Up @@ -32,11 +31,7 @@ func (l Leases) LatestByMac() map[string]Lease {

func ReadLeases(leaseFile string) (Leases, error) {
leasesContent := mustRead(leaseFile)
leases, err := Parse(leasesContent)
if err != nil {
return nil, fmt.Errorf("could not parse leases file:%w", err)
}
return leases, nil
return parse(leasesContent)
}

func mustRead(name string) string {
Expand Down
2 changes: 1 addition & 1 deletion internal/leases/leases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func TestFilterActive(t *testing.T) {
assert := assert.New(t)
l, err := Parse(LEASES_CONTENT)
l, err := parse(LEASES_CONTENT)
assert.NoError(err)
assert.Equal(Leases{}, l.FilterActive())
}
Expand Down
11 changes: 8 additions & 3 deletions internal/leases/parser.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package leases

import (
"errors"
"regexp"
"time"
)

const DATE_FORMAT = "2006/01/02 15:04:05"
const LEASE_REGEX = `(?ms)lease\s+(?P<ip>[^\s]+)\s+{.*?starts\s\d+\s(?P<begin>[\d\/]+\s[\d\:]+);.*?ends\s\d+\s(?P<end>[\d\/]+\s[\d\:]+);.*?hardware\sethernet\s(?P<mac>[\w\:]+);.*?}`

func Parse(contents string) (Leases, error) {
func parse(contents string) (Leases, error) {
leases := Leases{}
var re = regexp.MustCompile(LEASE_REGEX)
matches := re.FindAllStringSubmatch(contents, -1)
var errs []error
for _, m := range matches {
rm := make(map[string]string)
for i, name := range re.SubexpNames() {
Expand All @@ -21,11 +23,11 @@ func Parse(contents string) (Leases, error) {
}
begin, err := time.Parse(DATE_FORMAT, rm["begin"])
if err != nil {
panic(err)
errs = append(errs, err)
}
end, err := time.Parse(DATE_FORMAT, rm["end"])
if err != nil {
panic(err)
errs = append(errs, err)
}

l := Lease{
Expand All @@ -36,5 +38,8 @@ func Parse(contents string) (Leases, error) {
}
leases = append(leases, l)
}
if len(errs) > 0 {
return leases, errors.Join(errs...)
}
return leases, nil
}
2 changes: 1 addition & 1 deletion internal/leases/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ lease 192.168.2.30 {

func TestParse(t *testing.T) {
assert := assert.New(t)
l, err := Parse(LEASES_CONTENT)
l, err := parse(LEASES_CONTENT)
assert.NoError(err)

b, _ := time.Parse(DATE_FORMAT, "2019/06/27 13:30:21")
Expand Down
9 changes: 0 additions & 9 deletions internal/leases/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,3 @@ func NewReportItem(l Lease, log *zap.SugaredLogger) *ReportItem {
Log: log,
}
}

func (i *ReportItem) MacContainedIn(macs []string) bool {
for _, m := range macs {
if m == i.Mac {
return true
}
}
return false
}
50 changes: 38 additions & 12 deletions internal/reporter/reporter.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package reporter

import (
"net/netip"
"os"
"os/signal"
"slices"
"sync"
"syscall"
"time"

"github.com/metal-stack/metal-bmc/domain"
"github.com/metal-stack/metal-bmc/internal/leases"
"github.com/metal-stack/metal-bmc/pkg/config"
metalgo "github.com/metal-stack/metal-go"
"github.com/metal-stack/metal-go/api/client/machine"
"github.com/metal-stack/metal-go/api/models"
Expand All @@ -17,13 +19,13 @@ import (

// reporter reports information about bmc, bios and dhcp ip of bmc to metal-api
type reporter struct {
cfg *domain.Config
cfg *config.Config
log *zap.SugaredLogger
client metalgo.Client
}

// New will create a reporter for MachineIpmiReports
func New(log *zap.SugaredLogger, cfg *domain.Config, client metalgo.Client) (*reporter, error) {
func New(log *zap.SugaredLogger, cfg *config.Config, client metalgo.Client) (*reporter, error) {
return &reporter{
cfg: cfg,
log: log,
Expand All @@ -41,7 +43,11 @@ func (r reporter) Run() {
case <-periodic.C:
ls, err := leases.ReadLeases(r.cfg.LeaseFile)
if err != nil {
r.log.Fatalw("could not parse leases file", "error", err)
r.log.Errorw("could not parse leases file", "error", err)
}
if len(ls) == 0 {
r.log.Errorw("empty leases returned, nothing to report")
continue
}
active := ls.FilterActive()
byMac := active.LatestByMac()
Expand All @@ -54,6 +60,14 @@ func (r reporter) Run() {
wg.Add(len(byMac))

for _, l := range byMac {
if !r.isInAllowedCidr(l.Ip) {
continue
}

if slices.Contains(r.cfg.IgnoreMacs, l.Mac) {
continue
}

item := leases.NewReportItem(l, r.log)
go func() {
item.EnrichWithBMCDetails(r.cfg.IpmiPort, r.cfg.IpmiUser, r.cfg.IpmiPassword)
Expand All @@ -76,22 +90,34 @@ func (r reporter) Run() {
}
}

func (r reporter) isInAllowedCidr(ip string) bool {
parsedIP, err := netip.ParseAddr(ip)
if err != nil {
r.log.Errorw("given ip is not parsable", "ip", ip, "error", err)
return false
}
for _, cidr := range r.cfg.AllowedCidrs {
cidr := cidr
pfx, err := netip.ParsePrefix(cidr)
if err != nil {
return false
}
if pfx.Contains(parsedIP) {
return true
}
}
return false
}

// report will send all gathered information about machines to the metal-api
func (r reporter) report(items []*leases.ReportItem) error {
partitionID := r.cfg.PartitionID
reports := make(map[string]models.V1MachineIpmiReport)

for _, item := range items {
item := item
mac := item.Mac

if item.MacContainedIn(r.cfg.IgnoreMacs) {
continue
}

ip := item.Ip
if item.UUID == nil {
r.log.Errorw("could not determine uuid of device", "mac", mac, "ip", ip)
r.log.Errorw("could not determine uuid of device", "mac", item.Mac, "ip", item.Ip)
continue
}

Expand Down
8 changes: 6 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package main
import (
"fmt"

"github.com/metal-stack/metal-bmc/domain"
"github.com/metal-stack/metal-bmc/internal/bmc"
"github.com/metal-stack/metal-bmc/pkg/config"
metalgo "github.com/metal-stack/metal-go"

"github.com/metal-stack/metal-bmc/internal/reporter"
Expand All @@ -16,11 +16,15 @@ import (
)

func main() {
var cfg domain.Config
var cfg config.Config
if err := envconfig.Process("METAL_BMC", &cfg); err != nil {
panic(fmt.Errorf("bad configuration: %w", err))
}

if err := cfg.Validate(); err != nil {
panic(fmt.Errorf("bad configuration: %w", err))
}

level, err := zap.ParseAtomicLevel(cfg.LogLevel)
if err != nil {
panic(fmt.Errorf("can't initialize zap logger: %w", err))
Expand Down
15 changes: 14 additions & 1 deletion domain/config.go → pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package domain
package config

import (
"net/netip"
"net/url"
"time"
)
Expand All @@ -19,6 +20,7 @@ type Config struct {
IpmiUser string `required:"false" default:"ADMIN" desc:"the ipmi user" split_words:"true"`
IpmiPassword string `required:"false" default:"ADMIN" desc:"the ipmi password" split_words:"true"`
IgnoreMacs []string `required:"false" desc:"mac addresses to ignore" split_words:"true"`
AllowedCidrs []string `required:"false" desc:"filters dhcp leases" split_words:"true"`

// NSQ connection parameters
MQAddress string `required:"false" default:"localhost:4161" desc:"set the MQ server address" envconfig:"mq_address"`
Expand All @@ -34,3 +36,14 @@ type Config struct {
ConsoleCertFile string `required:"false" default:"cert.pem" desc:"cert file" envconfig:"console_cert_file"`
ConsoleKeyFile string `required:"false" default:"key.pem" desc:"key file" envconfig:"console_key_file"`
}

func (c *Config) Validate() error {
for _, cidr := range c.AllowedCidrs {
cidr := cidr
_, err := netip.ParsePrefix(cidr)
if err != nil {
return err
}
}
return nil
}

0 comments on commit dc1f71d

Please sign in to comment.