Skip to content

Commit

Permalink
M3-3857 Add: Cloud Firewall SDK methods (#6094)
Browse files Browse the repository at this point in the history
* Replace stub getFirewalls and getFirewallDevices with real requests

* Add createFirewall

* Add DELETE and POST for devices, GET for rules

* Add update methods and event messages

- Add update methods
- Add eventMessageGenerator handlers for the 6 new firewalls events

* Add documentation and deleteFirewall

* Add enableFirewall and disableFirewall helper methods

* Add firewall event types to EventAction union type

* Add some missing URL slashes

* Make UpdateFirewallPayload typing more precise

* Rename firewall_device_delete to firewall_device_remove
  • Loading branch information
Jskobos authored Feb 13, 2020
1 parent 1084e3a commit d129947
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 50 deletions.
7 changes: 7 additions & 0 deletions packages/linode-js-sdk/src/account/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ export type EventAction =
| 'domain_record_create'
| 'domain_record_updated'
| 'domain_record_delete'
| 'firewall_create'
| 'firewall_delete'
| 'firewall_device_add'
| 'firewall_device_remove'
| 'firewall_disable'
| 'firewall_enable'
| 'firewall_update'
| 'image_update'
| 'image_delete'
| 'lassie_reboot'
Expand Down
20 changes: 20 additions & 0 deletions packages/linode-js-sdk/src/firewalls/firewalls.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { array, number, object, string } from 'yup';

export const CreateFirewallSchema = object({
label: string(),
tags: array().of(string()),
rules: object().required('You must provide a set of Firewall rules.')
});

export const UpdateFirewallSchema = object().shape({
label: string(),
tags: array().of(string()),
status: string().oneOf(['enabled', 'disabled']) // 'deleted' is also a status but it's not settable
});

export const FirewallDeviceSchema = object({
type: string()
.oneOf(['linode', 'nodebalancer'])
.required('Device type is required.'),
id: number().required('ID is required.')
});
263 changes: 218 additions & 45 deletions packages/linode-js-sdk/src/firewalls/firewalls.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,221 @@
// import { API_ROOT } from '../constants';
// import Request, {
// setData,
// setMethod,
// setParams,
// setURL,
// setXFilter
// } from '../request';
import { BETA_API_ROOT } from '../constants';
import Request, {
setData,
setMethod,
setParams,
setURL,
setXFilter
} from '../request';
import { ResourcePage as Page } from '../types';
import { Firewall, FirewallDevice } from './types';

/**
* mocked GET firewalls
*/
export const getFirewalls = (
mockData: Firewall[],
params: any = {},
filter: any = {}
): Promise<Page<Firewall>> => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
data: mockData,
page: 1,
pages: 1,
results: mockData.length
});
}, 1000);
}).then((data: any) => {
return data;
});
};
import {
CreateFirewallSchema,
FirewallDeviceSchema,
UpdateFirewallSchema
} from './firewalls.schema';
import {
CreateFirewallPayload,
Firewall,
FirewallDevice,
FirewallDevicePayload,
FirewallRules,
UpdateFirewallPayload
} from './types';

// FIREWALLS

/**
* getFirewalls
*
* Returns a paginated list of all Cloud Firewalls on this account.
*/
export const getFirewalls = (params?: any, filters?: any) =>
Request<Page<Firewall>>(
setMethod('GET'),
setParams(params),
setXFilter(filters),
setURL(`${BETA_API_ROOT}/networking/firewalls`)
).then(response => response.data);

/**
* getFirewall
*
* Get a specific Firewall resource by its ID. The Firewall's Devices will not be
* returned in the response. Use getFirewallDevices() to view the Devices.
*
*/
export const getFirewall = (firewallID: number) =>
Request<Firewall>(
setMethod('GET'),
setURL(`${BETA_API_ROOT}/networking/firewalls/${firewallID}`)
).then(response => response.data);

/**
* createFirewall
*
* Creates a Firewall to filter network traffic. Use the `rules` property to
* create inbound and outbound access rules. Use the `devices` property to assign the
* Firewall to a Linode service.
* A Firewall can be assigned to multiple Linode services, and up to three active Firewalls
* can be assigned to a single Linode service. Additional disabled Firewalls can be
* assigned to a service, but they cannot be enabled if three other active Firewalls
* are already assigned to the same service.
*/
export const createFirewall = (data: CreateFirewallPayload) =>
Request<Firewall>(
setMethod('POST'),
setData(data, CreateFirewallSchema),
setURL(`${BETA_API_ROOT}/networking/firewalls`)
).then(response => response.data);

/**
* updateFirewall
*
* Updates the Cloud Firewall with the provided ID. Only label, tags, and status can be updated
* through this method.
*
*/
export const updateFirewall = (
firewallID: number,
data: UpdateFirewallPayload
) =>
Request<Firewall>(
setMethod('PUT'),
setData(data, UpdateFirewallSchema),
setURL(`${BETA_API_ROOT}/networking/firewalls/${firewallID}`)
).then(response => response.data);

/**
* enableFirewall
*
* Convenience method for enabling a Cloud Firewall. Calls updateFirewall internally
* with { status: 'enabled' }
*
*/
export const enableFirewall = (firewallID: number) =>
updateFirewall(firewallID, { status: 'enabled' });

/**
* disableFirewall
*
* Convenience method for disabling a Cloud Firewall. Calls updateFirewall internally
* with { status: 'disabled' }
*
*/
export const disableFirewall = (firewallID: number) =>
updateFirewall(firewallID, { status: 'disabled' });

/**
* deleteFirewall
*
* Deletes a single Cloud Firewall.
*
*/
export const deleteFirewall = (firewallID: number) =>
Request<{}>(
setMethod('DELETE'),
setURL(`${BETA_API_ROOT}/networking/firewalls/${firewallID}`)
).then(response => response.data);

// FIREWALL RULES

/**
* getFirewallRules
*
* Returns the current set of rules for a single Cloud Firewall.
*/
export const getFirewallRules = (
firewallID: number,
params?: any,
filters?: any
) =>
Request<Page<FirewallRules>>(
setMethod('GET'),
setParams(params),
setXFilter(filters),
setURL(`${BETA_API_ROOT}/networking/firewalls/${firewallID}/rules`)
).then(response => response.data);

/**
* updateFirewallRules
*
* Updates the inbound and outbound Rules for a Firewall. Using this endpoint will
* replace all of a Firewall's ruleset with the Rules specified in your request.
*/
export const updateFirewallRules = (firewallID: number, data: FirewallRules) =>
Request<FirewallRules>(
setMethod('PUT'),
setData(data), // Validation is too complicated for these; leave it to the API.
setURL(`${BETA_API_ROOT}/networking/firewalls/${firewallID}/rules`)
).then(response => response.data);

// DEVICES

/**
* getFirewallDevices
*
* Returns a paginated list of a Firewall's Devices. A Firewall Device assigns a
* Firewall to a Linode service (referred to as the Device's `entity`).
*/
export const getFirewallDevices = (
id: number,
mockData: FirewallDevice[]
): Promise<Page<FirewallDevice>> => {
return new Promise(resolve => {
setTimeout(() => {
resolve({
data: mockData,
page: 1,
pages: 1,
results: mockData.length
});
});
}).then((data: any) => data);
};
firewallID: number,
params?: any,
filters?: any
) =>
Request<Page<FirewallDevice>>(
setMethod('GET'),
setParams(params),
setXFilter(filters),
setURL(`${BETA_API_ROOT}/networking/firewalls/${firewallID}/devices`)
).then(response => response.data);

/**
* getFirewallDevice
*
* Returns information about a single Firewall Device. A Firewall Device assigns a
* Firewall to a Linode service (referred to as the Device's `entity`).
*/
export const getFirewallDevice = (firewallID: number, deviceID: number) =>
Request<FirewallDevice>(
setMethod('GET'),
setURL(
`${BETA_API_ROOT}/networking/firewalls/${firewallID}/devices/${deviceID}`
)
).then(response => response.data);

/**
* addFirewallDevice
*
* Creates a Firewall Device, which assigns a Firewall to a Linode service (referred to
* as the Device's `entity`).
* A Firewall can be assigned to multiple Linode services, and up to three active Firewalls can
* be assigned to a single Linode service. Additional disabled Firewalls can be
* assigned to a service, but they cannot be enabled if three other active Firewalls
* are already assigned to the same service.
* Creating a Firewall Device will apply the Rules from a Firewall to a Linode service.
* A `firewall_device_add` Event is generated when the Firewall Device is added successfully.
*/
export const addFirewallDevice = (
firewallID: number,
data: FirewallDevicePayload
) =>
Request<FirewallDevice>(
setMethod('POST'),
setURL(`${BETA_API_ROOT}/networking/firewalls/${firewallID}/devices`),
setData(data, FirewallDeviceSchema)
).then(response => response.data);

/**
* deleteFirewallDevice
*
* Removes a Firewall Device, which removes a Firewall from the Linode service it was
* assigned to by the Device. This will remove all of the Firewall's Rules from the Linode
* service. If any other Firewalls have been assigned to the Linode service, then those Rules
* will remain in effect.
*/
export const deleteFirewallDevice = (firewallID: number, deviceID: number) =>
Request<{}>(
setMethod('DELETE'),
setURL(
`${BETA_API_ROOT}/networking/firewalls/${firewallID}/devices/${deviceID}`
)
).then(response => response.data);
25 changes: 24 additions & 1 deletion packages/linode-js-sdk/src/firewalls/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export type FirewallStatus = 'enabled' | 'disabled' | 'deleted';

export type FirewallRuleProtocol = 'ALL' | 'TCP' | 'UDP' | 'ICMP';

export type FirewallDeviceEntityType = 'linode' | 'nodebalancer';

export interface Firewall {
id: number;
status: FirewallStatus;
Expand Down Expand Up @@ -29,7 +31,7 @@ export interface FirewallRuleType {

export interface FirewallDeviceEntity {
id: number;
type: 'linode' | 'nodebalancer';
type: FirewallDeviceEntityType;
label: string;
url: string;
}
Expand All @@ -38,3 +40,24 @@ export interface FirewallDevice {
id: number;
entity: FirewallDeviceEntity;
}

export interface CreateFirewallPayload {
label?: string;
tags?: string[];
rules: FirewallRules;
devices?: {
linodes?: number[];
nodebalancers?: number[];
};
}

export interface UpdateFirewallPayload {
label?: string;
tags?: string[];
status?: Omit<FirewallStatus, 'deleted'>;
}

export interface FirewallDevicePayload {
id: number;
type: FirewallDeviceEntityType;
}
5 changes: 4 additions & 1 deletion packages/manager/src/containers/firewalls.container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { ThunkDispatch } from 'src/store/types';
import { GetAllData } from 'src/utilities/getAll';

interface DispatchProps {
getFirewalls: (params: any, filters: any) => Promise<GetAllData<Firewall[]>>;
getFirewalls: (
params?: any,
filters?: any
) => Promise<GetAllData<Firewall[]>>;
}

/* tslint:disable-next-line */
Expand Down
23 changes: 23 additions & 0 deletions packages/manager/src/eventMessageGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,29 @@ export const eventMessageCreators: { [index: string]: CreatorsForStatus } = {
notification: e =>
`A domain record has been deleted from ${e.entity!.label}`
},
firewall_enable: {
notification: e => `Firewall ${e.entity?.label ?? ''} has been enabled.`
},
firewall_disable: {
notification: e => `Firewall ${e.entity?.label ?? ''} has been disabled.`
},
firewall_update: {
notification: e => `Firewall ${e.entity?.label ?? ''} has been updated.`
},
firewall_device_add: {
notification: e =>
`A device has been added to Firewall ${e.entity?.label ?? ''}.`
},
firewall_device_remove: {
notification: e =>
`A device has been removed from Firewall ${e.entity?.label ?? ''}.`
},
firewall_delete: {
notification: e => `Firewall ${e.entity?.label ?? ''} has been deleted.`
},
firewall_create: {
notification: e => `Firewall ${e.entity?.label ?? ''} has been created.`
},
image_update: {
notification: e => `Image ${e.entity?.label ?? ''} has been updated.`
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const FirewallLanding: React.FC<CombinedProps> = props => {
firewallsLastUpdated === 0 &&
!firewallsLoading
) {
props.getFirewalls({ hello: 'hello' }, { world: 'world' });
props.getFirewalls();
}
}, [firewallsLastUpdated, firewallsLoading, firewallsKeys]);

Expand Down
Loading

0 comments on commit d129947

Please sign in to comment.