1- import { createApiClient , modules } from "dots-wrapper" ;
2- import { IListRequest } from "dots-wrapper/dist/types/list-request" ;
1+ import { createApiClient , modules } from "dots-wrapper" ;
2+ import { IListRequest } from "dots-wrapper/dist/types/list-request" ;
33
4- import { ActionConfig } from "./utils" ;
4+ import { ActionConfig } from "./utils" ;
5+
6+ import { IFirewallInboundRule , IFirewallOutboundRule } from "dots-wrapper/dist/modules/firewall" ;
7+ import { config } from "process" ;
58
6- import { IFirewallInboundRule , IFirewallOutboundRule } from "dots-wrapper/dist/modules/firewall" ;
79
810interface ClientInterface {
911 firewall : Readonly < {
@@ -36,53 +38,70 @@ export async function getFirewall({firewall: firewallClient}: ClientInterface, n
3638 throw new Error ( `The firewall with name '${ name } ', doesn't exist.` ) ;
3739 }
3840
41+ // in case the firewall has no inbound rules
42+ firewall . inbound_rules = firewall . inbound_rules || [ ] ;
43+
3944 return firewall ;
4045}
4146
42- function applyRule ( config : ActionConfig , rule : IFirewallInboundRule = { protocol : '' , ports : '' , sources : { } } ) {
47+ function applyRule ( config : ActionConfig , rule : IFirewallInboundRule = { protocol : '' , ports : '' , sources : { } } ) : IFirewallInboundRule | null {
4348 const cloneRule = { ...rule } ;
4449 const { port, action, protocol, IP } = config ;
4550
46- if ( rule . ports != port . toString ( ) || rule . protocol != protocol )
47- return cloneRule ;
4851
52+ if ( ! cloneRule . protocol ) {
53+ cloneRule . protocol = protocol ;
54+ }
55+ if ( ! cloneRule . ports ) {
56+ cloneRule . ports = port . toString ( ) ;
57+ }
4958 if ( ! cloneRule . sources . addresses ) {
5059 cloneRule . sources . addresses = [ ] ;
5160 }
61+
5262 const addresses = cloneRule . sources . addresses ;
5363 if ( action == "add" ) {
5464 if ( ! addresses . includes ( IP ) ) {
5565 addresses . push ( IP ) ;
5666 }
5767 } else if ( action == "remove" ) {
5868 cloneRule . sources . addresses = addresses . filter ( address => address != IP ) ;
69+
5970 }
60-
61-
71+
72+ if ( cloneRule . sources ?. addresses . length == 0 ) {
73+ return null ;
74+ }
75+
6276 return cloneRule ;
6377}
6478
65- export function generateInboundRules ( oldRules : IFirewallInboundRule [ ] , config : ActionConfig ) : IFirewallInboundRule [ ] {
79+ export function generateInboundRules ( oldRules : IFirewallInboundRule [ ] = [ ] , config : ActionConfig ) : IFirewallInboundRule [ ] {
6680 const { port, action, protocol } = config ;
6781 const existingRules = oldRules . filter ( r => r . ports == port . toString ( ) && r . protocol == protocol ) ;
6882
6983 if ( ! existingRules . length ) {
70- oldRules . push ( applyRule ( config ) ) ;
84+ const newRule = applyRule ( config ) ;
85+ if ( newRule ) {
86+ oldRules . push ( newRule ) ;
87+ }
7188 return oldRules ;
7289 }
7390
74- return oldRules . map ( ( r , index ) => {
91+ return oldRules . reduce ( ( out , r , index ) => {
7592 if ( action == "remove" || ( action == "add" && index == 0 ) ) {
76- return applyRule ( config , r )
93+ const newRule = applyRule ( config , r ) ;
94+ if ( newRule )
95+ out . push ( newRule )
7796 } else {
78- return r ;
97+ out . push ( r ) ;
7998 }
80- } ) ;
81-
99+ return out ;
100+ } , [ ] as IFirewallInboundRule [ ] ) ;
82101}
83102
84103export async function updateInboundRules (
85- { firewall : firewallClient } : ClientInterface ,
104+ { firewall : firewallClient } : ClientInterface ,
86105 firewall : modules . firewall . IFirewall ,
87106 inboundRules : IFirewallInboundRule [ ] ,
88107 dryrun = true
@@ -95,27 +114,59 @@ export async function updateInboundRules(
95114
96115 const updated = {
97116 ...firewall ,
98- inbound_rules : inboundRules ,
117+ inbound_rules : inboundRules . length ? inboundRules : [ ] ,
99118 outbound_rules : prepareOutboundRules ( firewall . outbound_rules )
100119 } ;
101120
102- const {
103- data : { firewall : response }
104- } = await firewallClient . updateFirewall ( updated ) ;
121+ try {
122+
123+ let maxRetries = 10 ;
124+ const { data : { firewall : response } } = await firewallClient . updateFirewall ( updated ) ;
125+ let status = response . status ;
126+ const firewallId = ( response . id as string ) ;
127+
128+ /*
129+ wait for DO to update the droplets using this firewall
130+ */
131+ while ( true ) {
132+
133+ maxRetries -- ;
134+ if ( maxRetries < 0 ) {
135+ break ; // give up
136+ }
137+ console . log ( `DO status: ${ status } ` ) ;
138+ if ( status != "waiting" ) {
139+ break ;
140+ }
141+
142+ console . log ( " waiting for DO to update the droplets using this firewall..." ) ;
143+ await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ;
144+
145+ const { data : { firewall : fw } } = await firewallClient . getFirewall ( { firewall_id : firewallId } ) ;
146+ status = fw ?. status || "errored" ;
147+
148+ }
105149
106- console . log ( ( response as any ) . status ) ;
150+ } catch ( e ) {
151+ console . error ( "FW Update failed. updated : %j" , updated ) ;
152+ console . error ( "FW Update failed. inboundRules: %j" , inboundRules ) ;
153+ console . error ( e ) ;
154+ }
107155}
108156
109- export function printFirewallRules ( inboundRules : IFirewallInboundRule [ ] , title = "" ) {
157+ export function printFirewallRules ( inboundRules : IFirewallInboundRule [ ] = [ ] , title = "" ) {
110158 console . log ( "----------------------" ) ;
111159 console . log ( `Firewall Inbound Rules ${ title } ` ) ;
112160 console . log ( "----------------------" ) ;
161+ if ( inboundRules . length == 0 ) {
162+ console . log ( "** no rules defined **" ) ;
163+ }
113164 inboundRules . forEach ( rule => {
114- console . log ( `${ rule . ports } ::${ rule . protocol } - ${ rule . sources . addresses } ` ) ;
165+ console . log ( `${ rule . ports } ::${ rule . protocol } - ${ rule . sources ? .addresses } ` ) ;
115166 } ) ;
116167}
117168
118- function prepareOutboundRules ( outboundRules : IFirewallOutboundRule [ ] ) : IFirewallOutboundRule [ ] {
169+ function prepareOutboundRules ( outboundRules : IFirewallOutboundRule [ ] = [ ] ) : IFirewallOutboundRule [ ] {
119170 return outboundRules . map ( rule => {
120171 const clonedRule = { ...rule } ;
121172 if ( clonedRule . ports == "all" ) {
0 commit comments