check point of code to identify and provision switches
Change-Id: I692d83127cbb718f03d359911689d0f688fa4a3d
diff --git a/switchq/switchq.go b/switchq/switchq.go
new file mode 100644
index 0000000..922f1ba
--- /dev/null
+++ b/switchq/switchq.go
@@ -0,0 +1,102 @@
+package main
+
+import (
+ "fmt"
+ "github.com/kelseyhightower/envconfig"
+ "log"
+ "time"
+)
+
+type Config struct {
+ StorageURL string `default:"memory:///switchq/vendors.json" envconfig:"storage_url"`
+ AddressURL string `default:"file:///switchq/dhcp_harvest.inc" envconfig:"address_url"`
+ PollInterval string `default:"1m" envconfig:"poll_interval"`
+ ProvisionTTL string `default:"1h" envconfig:"check_ttl"`
+
+ storage Storage
+ addressSource AddressSource
+ interval time.Duration
+ ttl time.Duration
+}
+
+func checkError(err error, msg string, args ...interface{}) {
+ if err != nil {
+ log.Fatalf(msg, args...)
+ }
+}
+
+func (c *Config) processRecord(rec AddressRec) error {
+ if c.ttl == 0 {
+ // One provisioning only please
+ return nil
+ }
+
+ ok, err := c.storage.Switchq(rec.MAC)
+ if err != nil {
+ return fmt.Errorf("unable to determine ventor of MAC '%s' (%s)", rec.MAC, err)
+ }
+
+ if !ok {
+ // Not something we care about
+ log.Printf("[debug] host with IP '%s' and MAC '%s' and named '%s' not a known switch type",
+ rec.IP, rec.MAC, rec.Name)
+ return nil
+ }
+
+ last, err := c.storage.LastProvisioned(rec.MAC)
+ if err != nil {
+ return err
+ }
+ if last == nil || time.Since(*last) > c.ttl {
+ log.Printf("[debug] time to provision %s", rec.MAC)
+ }
+ return nil
+}
+
+func main() {
+
+ var err error
+ config := Config{}
+ envconfig.Process("SWITCHQ", &config)
+
+ config.storage, err = NewStorage(config.StorageURL)
+ checkError(err, "Unable to create require storage for specified URL '%s' : %s", config.StorageURL, err)
+
+ config.addressSource, err = NewAddressSource(config.AddressURL)
+ checkError(err, "Unable to create required address source for specified URL '%s' : %s", config.AddressURL, err)
+
+ config.interval, err = time.ParseDuration(config.PollInterval)
+ checkError(err, "Unable to parse specified poll interface '%s' : %s", config.PollInterval, err)
+
+ config.ttl, err = time.ParseDuration(config.ProvisionTTL)
+ checkError(err, "Unable to parse specified provision TTL value of '%s' : %s", config.ProvisionTTL, err)
+
+ log.Printf(`Configuration:
+ Storage URL: %s
+ Poll Interval: %s
+ Address Source: %s
+ Provision TTL: %s`,
+ config.StorageURL, config.PollInterval, config.AddressURL, config.ProvisionTTL)
+
+ // We use two methods to attempt to find the MAC (hardware) address associated with an IP. The first
+ // is to look in the table. The second is to send an ARP packet.
+ for {
+ log.Printf("[info] Checking for switches @ %s", time.Now())
+ addresses, err := config.addressSource.GetAddresses()
+
+ if err != nil {
+ log.Printf("[error] unable to read addresses from address source : %s", err)
+ } else {
+ log.Printf("[info] Queried %d addresses from address source", len(addresses))
+
+ for _, rec := range addresses {
+ log.Printf("[debug] Processing %s(%s, %s)", rec.Name, rec.IP, rec.MAC)
+ if err := config.processRecord(rec); err != nil {
+ log.Printf("[error] Error when processing IP '%s' : %s", rec.IP, err)
+ }
+ }
+ }
+
+ time.Sleep(config.interval)
+ }
+}