blob: 853b9e5768663ad543c2ddd80aa78b9cc6f48a85 [file] [log] [blame]
Sergiusz Bazanski1fad2e52019-08-01 20:16:27 +02001package model
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7
8 pb "code.hackerspace.pl/hscloud/bgpwtf/cccampix/proto"
9 "github.com/golang/glog"
10 "github.com/jmoiron/sqlx"
11)
12
13func (m *sqlModel) RecordPeeringDBPeerRouters(ctx context.Context, members []*pb.PeeringDBMember) error {
14 tx := m.db.MustBeginTx(ctx, &sql.TxOptions{})
15 defer tx.Rollback()
16
17 for _, member := range members {
18 // Get existing routers for peer.
19 q := `
20 SELECT peer_routers.id, peer_routers.v4, peer_routers.v6
21 FROM peer_routers
22 LEFT JOIN peers ON (peer_routers.peer_id = peers.id)
23 WHERE peer_routers.source = 'from-peeringdb'
24 AND peers.asn = ?
25 `
26 q = tx.Rebind(q)
27 existing := []sqlPeerRouter{}
28 if err := tx.SelectContext(ctx, &existing, q, fmt.Sprintf("%d", member.Asn)); err != nil {
29 return fmt.Errorf("SELECT peerRouters: %v", err)
30 }
31
32 // Find all routers that need to be deleted because they're outdated.
33 // We do not attempt updates, only removals/recreations.
34
35 // UUID -> bool
36 toDelete := make(map[string]bool)
37
38 for _, ex := range existing {
39 // Try to find a requested router with same IP addresses.
40 found := false
41 for _, router := range member.Routers {
42 if router.Ipv4 == ex.V4.String && router.Ipv6 == ex.V6.String {
43 found = true
44 break
45 }
46 }
47
48 // Not found, mark for deletion.
49 if !found {
50 toDelete[ex.ID] = true
51 }
52 }
53
54 // Find all routers that need to be created.
55 toAdd := []sqlPeerRouter{}
56 for _, router := range member.Routers {
57 // Try to find an existing router with same IP addresses.
58 found := false
59 for _, ex := range existing {
60 if router.Ipv4 == ex.V4.String && router.Ipv6 == ex.V6.String {
61 found = true
62 break
63 }
64 }
65 // Not found, mark for creation.
66 if !found {
67 ta := sqlPeerRouter{
68 Source: "from-peeringdb",
69 ASN: fmt.Sprintf("%d", member.Asn),
70 }
71 if router.Ipv6 != "" {
72 ta.V6.String = router.Ipv6
73 ta.V6.Valid = true
74 }
75 if router.Ipv4 != "" {
76 ta.V4.String = router.Ipv4
77 ta.V4.Valid = true
78 }
79 toAdd = append(toAdd, ta)
80 }
81 }
82
83 if len(toDelete) > 0 {
84 glog.Infof("RecordPeeringDBPeers: deleting %v", toDelete)
85 }
86 if len(toAdd) > 0 {
87 glog.Infof("RecordPeeringDBPeers: adding %+v", toAdd)
88 }
89
90 // Delete any routers, if needed.
91 if len(toDelete) > 0 {
92 // Get list of IDs to delete.
93 deleteIds := make([]string, len(toDelete))
94 i := 0
95 for id, _ := range toDelete {
96 deleteIds[i] = id
97 i += 1
98 }
99 query, args, err := sqlx.In("DELETE FROM peer_Routers WHERE id IN (?)", deleteIds)
100 if err != nil {
101 return fmt.Errorf("DELETE peerRouters: %v", err)
102 }
103 query = tx.Rebind(query)
104 _, err = tx.ExecContext(ctx, query, args...)
105 if err != nil {
106 return fmt.Errorf("DELETE peerRouters: %v", err)
107 }
108 }
109
110 // Add any routers, if needed.
111 for _, ta := range toAdd {
112 q := `
113 INSERT INTO peer_routers
114 (peer_id, v6, v4, source)
115 SELECT
116 peers.id, :v6, :v4, :source
117 FROM
118 peers
119 WHERE peers.asn = :asn
120 `
121 if _, err := tx.NamedExecContext(ctx, q, ta); err != nil {
122 return fmt.Errorf("INSERT peerRouters: %v", err)
123 }
124 }
125 }
126
127 return tx.Commit()
128}