diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 2cf0ae6..5bdc26d 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@apiclient.xyz/hetznercloud', - version: '1.0.18', + version: '1.1.0', description: 'an unofficial api client for the hetzner cloud api' } diff --git a/ts/classes.firewall.ts b/ts/classes.firewall.ts index e69de29..92ebc81 100644 --- a/ts/classes.firewall.ts +++ b/ts/classes.firewall.ts @@ -0,0 +1,74 @@ +// Hetzner Cloud Firewall Class +import type { HetznerAccount } from './classes.account.js'; +import * as plugins from './hetznercloud.plugins.js'; +import * as types from './types.js'; + +export class HetznerFirewall { + // STATIC + public static create = async ( + hetznerAccountRefArg: HetznerAccount, + optionsArg: { + name: string; + labels?: {[key: string]: string}, + rules: types.IFirewall['rules'], + } + ) => { + const firewall = new HetznerFirewall(hetznerAccountRefArg); + + const createFirewallUrl = '/firewalls'; + const createFirewallPayload: types.TFirewallCreateRequestBody = { + name: optionsArg.name, + labels: optionsArg.labels || {} as any, + rules: optionsArg.rules + }; + const response = await firewall.hetznerAccountRef.request( + 'POST', + createFirewallUrl, + createFirewallPayload + ); + firewall.data = (response.body as types.TFirewallCreateResponseBody).firewall; + return firewall; + } + + public static getFirewalls = async (hetznerAccountRefArg: HetznerAccount) => { + const firewallsGetUrl = '/firewalls'; + const response = await hetznerAccountRefArg.request('GET', firewallsGetUrl, {}); + const firewallsDataArray = (response.body as types.TFirewallsGetResponseBody).firewalls; + const firewalls: HetznerFirewall[] = []; + for (const firewallData of firewallsDataArray) { + const firewall = new HetznerFirewall(hetznerAccountRefArg); + firewall.data = firewallData; + firewalls.push(firewall); + } + return firewalls; + } + + public static getFirewallsByLabel = async (hetznerAccountRefArg: HetznerAccount, labelObject: {[key: string]: string}) => { + const firewalls = await HetznerFirewall.getFirewalls(hetznerAccountRefArg); + const results: HetznerFirewall[] = []; + for (const firewall of firewalls) { + let isMatch = true; + for (const key in labelObject) { + if (firewall.data.labels[key] !== labelObject[key]) { + isMatch = false; + } + } + if (isMatch) { + results.push(firewall); + } + } + return results; + } + + // INSTANCE + public data: types.IFirewall; + public hetznerAccountRef: HetznerAccount; + + constructor(hetznerAccountRefArg: HetznerAccount) { + this.hetznerAccountRef = hetznerAccountRefArg; + } + + public async delete() { + await this.hetznerAccountRef.request('DELETE', `/firewalls/${this.data.id}`, {}); + } +} \ No newline at end of file diff --git a/ts/classes.volume.ts b/ts/classes.volume.ts new file mode 100644 index 0000000..024ecf8 --- /dev/null +++ b/ts/classes.volume.ts @@ -0,0 +1,77 @@ +import type { HetznerAccount } from './classes.account.js'; +import type { HetznerServer } from './classes.server.js'; +import * as plugins from './hetznercloud.plugins.js'; +import * as types from './types.js'; + +export class Volume { + public static create = async ( + hetznerAccountRefArg: HetznerAccount, + optionsArg: { + name: string; + size: number; + location: types.THetznerCloudLocationName; + labels?: {[key: string]: string}, + server: HetznerServer, + } + ) => { + const volume = new Volume(hetznerAccountRefArg); + + const createVolumeUrl = '/volumes'; + const createVolumePayload: types.TVolumeCreateRequestBody = { + name: optionsArg.name, + size: optionsArg.size, + location: optionsArg.location, + labels: optionsArg.labels || {} as any, + server: optionsArg.server.data.id, + format: 'xfs' + }; + const response = await volume.hetznerAccountRef.request( + 'POST', + createVolumeUrl, + createVolumePayload + ); + volume.data = (response.body as types.TVolumeCreateResponseBody).volume; + return volume; + } + + public static getVolumes = async (hetznerAccountRefArg: HetznerAccount) => { + const volumesGetUrl = '/volumes'; + const response = await hetznerAccountRefArg.request('GET', volumesGetUrl, {}); + const volumesDataArray = (response.body as types.TVolumeGetResponseBody).volumes; + const volumes: Volume[] = []; + for (const volumeData of volumesDataArray) { + const volume = new Volume(hetznerAccountRefArg); + volume.data = volumeData; + volumes.push(volume); + } + return volumes; + } + + public static getVolumesByLabel = async (hetznerAccountRefArg: HetznerAccount, labelObject: {[key: string]: string}) => { + const volumes = await Volume.getVolumes(hetznerAccountRefArg); + const results: Volume[] = []; + for (const volume of volumes) { + let isMatch = true; + for (const key in labelObject) { + if (volume.data.labels[key] !== labelObject[key]) { + isMatch = false; + } + } + if (isMatch) { + results.push(volume); + } + } + return results; + } + + public data: types.IVolume; + public hetznerAccountRef: HetznerAccount; + + constructor(hetznerAccountRefArg: HetznerAccount) { + this.hetznerAccountRef = hetznerAccountRefArg; + } + + public delete = async () => { + await this.hetznerAccountRef.request('DELETE', `/volumes/${this.data.id}`, {}); + } +} \ No newline at end of file diff --git a/ts/index.ts b/ts/index.ts index 767b651..7590326 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -1,2 +1,4 @@ export * from './classes.account.js'; export * from './classes.server.js'; +export * from './classes.volume.js'; +export * from './classes.firewall.js'; diff --git a/ts/types.ts b/ts/types.ts index 4712391..23261d3 100644 --- a/ts/types.ts +++ b/ts/types.ts @@ -9,6 +9,7 @@ export type TServersGetRequestBody = {}; export type TServersGetResponseBody = plugins.hetznerOpenapi.paths['/servers']['get']['responses']['200']['content']['application/json']; export type TServerCreateRequestBody = plugins.hetznerOpenapi.paths['/servers']['post']['requestBody']['content']['application/json']; export type TServerCreateResponseBody = plugins.hetznerOpenapi.paths['/servers']['post']['responses']['201']['content']['application/json']; +export type TServerDeleteRequestBody = plugins.hetznerOpenapi.paths['/servers/{id}']['delete']; // server types export type THetznerCloudServerName = @@ -39,4 +40,20 @@ export type THetznerCloudServerName = | 'cpx90'; // location types -export type THetznerCloudLocationName = 'fsn1' | 'nbg1' | 'hel1' | 'ash' | 'hil'; \ No newline at end of file +export type THetznerCloudLocationName = 'fsn1' | 'nbg1' | 'hel1' | 'ash' | 'hil'; + +// volumes +export type IVolume = plugins.hetznerOpenapi.paths['/volumes/{id}']['get']['responses']['200']['content']['application/json']['volume']; +export type TVolumeGetRequestBody = {}; +export type TVolumeGetResponseBody = plugins.hetznerOpenapi.paths['/volumes']['get']['responses']['200']['content']['application/json']; +export type TVolumeCreateRequestBody = plugins.hetznerOpenapi.paths['/volumes']['post']['requestBody']['content']['application/json']; +export type TVolumeCreateResponseBody = plugins.hetznerOpenapi.paths['/volumes']['post']['responses']['201']['content']['application/json']; +export type TVolumeDeleteRequestBody = plugins.hetznerOpenapi.paths['/volumes/{id}']['delete']; + +// firewalls +export type IFirewall = plugins.hetznerOpenapi.paths['/firewalls/{id}']['get']['responses']['200']['content']['application/json']['firewall']; +export type TFirewallsGetRequestBody = {}; +export type TFirewallsGetResponseBody = plugins.hetznerOpenapi.paths['/firewalls']['get']['responses']['200']['content']['application/json']; +export type TFirewallCreateRequestBody = plugins.hetznerOpenapi.paths['/firewalls']['post']['requestBody']['content']['application/json']; +export type TFirewallCreateResponseBody = plugins.hetznerOpenapi.paths['/firewalls']['post']['responses']['201']['content']['application/json']; +export type TFirewallDeleteRequestBody = plugins.hetznerOpenapi.paths['/firewalls/{id}']['delete'];