package cluster import ( "io/fs" "os" "git.jpi.io/amery/jpictl/pkg/rings" ) var ( _ WireguardConfigPruner = (*Cluster)(nil) _ WireguardConfigPruner = (*Zone)(nil) _ WireguardConfigPruner = (*Machine)(nil) _ WireguardConfigWriter = (*Cluster)(nil) _ WireguardConfigWriter = (*Zone)(nil) _ WireguardConfigWriter = (*Machine)(nil) _ WireguardConfigSyncer = (*Cluster)(nil) _ WireguardConfigSyncer = (*Zone)(nil) _ WireguardConfigSyncer = (*Machine)(nil) _ WireguardKeysWriter = (*Cluster)(nil) _ WireguardKeysWriter = (*Zone)(nil) _ WireguardKeysWriter = (*Machine)(nil) ) // A WireguardConfigPruner deletes wgN.conf on all machines under // its scope with the specified ring disabled type WireguardConfigPruner interface { PruneWireguardConfig(ring rings.RingID) error } // PruneWireguardConfig removes wgN.conf files of machines with // the corresponding ring disabled on all zones func (m *Cluster) PruneWireguardConfig(ring rings.RingID) error { return pruneWireguardConfig(m, ring) } // PruneWireguardConfig removes wgN.conf files of machines with // the corresponding ring disabled. func (z *Zone) PruneWireguardConfig(ring rings.RingID) error { return pruneWireguardConfig(z, ring) } func pruneWireguardConfig(m MachineIterator, ring rings.RingID) error { var err error m.ForEachMachine(func(p *Machine) bool { err = p.PruneWireguardConfig(ring) if os.IsNotExist(err) { // ignore err = nil } return err != nil }) return err } // PruneWireguardConfig deletes the wgN.conf file if its // presence on the ring is disabled func (m *Machine) PruneWireguardConfig(ring rings.RingID) error { _, ok := m.getRingInfo(ring) if !ok { return m.RemoveWireguardConfig(ring) } return nil } // A WireguardConfigWriter rewrites all wgN.conf on all machines under // its scope attached to that ring type WireguardConfigWriter interface { WriteWireguardConfig(ring rings.RingID) error } // WriteWireguardConfig rewrites all wgN.conf on all machines // attached to that ring func (m *Cluster) WriteWireguardConfig(ring rings.RingID) error { switch ring { case rings.RingZeroID: return writeWireguardConfig(m, m, ring) default: return ErrInvalidRing(ring) } } // WriteWireguardConfig rewrites all wgN.conf on all machines // on the Zone attached to that ring func (z *Zone) WriteWireguardConfig(ring rings.RingID) error { switch ring { case rings.RingZeroID: return writeWireguardConfig(z.zones, z.zones, ring) default: return ErrInvalidRing(ring) } } func writeWireguardConfig(z ZoneIterator, m MachineIterator, ring rings.RingID) error { r, err := NewRing(z, m, ring) if err != nil { return err } r.ForEachMachine(func(p *Machine) bool { err = p.writeWireguardRingConfig(r) return err != nil }) return err } // WriteWireguardConfig rewrites the wgN.conf file of this Machine // if enabled func (m *Machine) WriteWireguardConfig(ring rings.RingID) error { r, err := NewRing(m.zone.zones, m.zone, ring) if err != nil { return err } return m.writeWireguardRingConfig(r) } func (m *Machine) writeWireguardRingConfig(r *Ring) error { ring, err := AsWireguardInterfaceID(r.ID) if err != nil { return err } wg, err := r.ExportConfig(m) if err != nil { return nil } f, err := m.CreateTruncFile(ring.ConfFile()) if err != nil { return err } defer f.Close() _, err = wg.WriteTo(f) return err } // A WireguardConfigSyncer updates all wgN.conf on all machines under // its scope reflecting the state of the ring type WireguardConfigSyncer interface { SyncWireguardConfig(ring rings.RingID) error } // SyncWireguardConfig updates all wgN.conf files for the specified // ring func (m *Cluster) SyncWireguardConfig(ring rings.RingID) error { switch ring { case rings.RingZeroID: return syncWireguardConfig(m, m, ring) default: return ErrInvalidRing(ring) } } // SyncWireguardConfig updates all wgN.conf files for the specified // ring func (z *Zone) SyncWireguardConfig(ring rings.RingID) error { switch ring { case rings.RingZeroID: return syncWireguardConfig(z.zones, z.zones, ring) default: return ErrInvalidRing(ring) } } func syncWireguardConfig(z ZoneIterator, m MachineIterator, ring rings.RingID) error { r, err := NewRing(z, m, ring) if err != nil { return err } r.ForEachMachine(func(p *Machine) bool { if _, ok := p.getRingInfo(ring); ok { err = p.writeWireguardRingConfig(r) } else { err = p.RemoveWireguardConfig(ring) } return err != nil }) return err } // SyncWireguardConfig updates all wgN.conf files for the specified // ring func (m *Machine) SyncWireguardConfig(ring rings.RingID) error { return m.zone.SyncWireguardConfig(ring) } // A WireguardKeysWriter writes the Wireguard Keys for all machines // under its scope for the specified ring type WireguardKeysWriter interface { WriteWireguardKeys(ring rings.RingID) error } // WriteWireguardKeys rewrites all wgN.{key,pub} files func (m *Cluster) WriteWireguardKeys(ring rings.RingID) error { return writeWireguardKeys(m, ring) } // WriteWireguardKeys rewrites all wgN.{key,pub} files on this zone func (z *Zone) WriteWireguardKeys(ring rings.RingID) error { return writeWireguardKeys(z, ring) } func writeWireguardKeys(m MachineIterator, ring rings.RingID) error { var err error m.ForEachMachine(func(p *Machine) bool { err = p.WriteWireguardKeys(ring) if os.IsNotExist(err) { // ignore err = nil } return err != nil }) return err } // WriteWireguardKeys writes the wgN.key/wgN.pub files func (m *Machine) WriteWireguardKeys(ringID rings.RingID) error { var err error var key, pub string var ri *RingInfo ri, _ = m.getRingInfo(ringID) if ri != nil { key = ri.Keys.PrivateKey.String() pub = ri.Keys.PublicKey.String() } switch { case key == "": return fs.ErrNotExist case pub == "": pub = ri.Keys.PrivateKey.Public().String() } keyFile, pubFile, _ := ri.Ring.Files() err = m.WriteStringFile(key+"\n", keyFile) if err != nil { return err } err = m.WriteStringFile(pub+"\n", pubFile) if err != nil { return err } return nil }