diff --git a/README.md b/README.md index b13e653..7ffc816 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,14 @@ should align to these tenets, or propose an adjustment to the tenets. - Azure Reserved - DNS Mapping - Broadcast Address (last network address) +### OCI mode ([docs](https://docs.oracle.com/en-us/iaas/Content/Network/Concepts/overview.htm#Reserved__reserved_subnet)): + +- Smallest subnet: /30 +- Three reserved addresses per subnet: + - Network Address (network + 0) + - OCI Reserved - Default Gateway Address (network + 1) + - Broadcast Address (last network address) + ## Building From Source If you have a more opinionated best-practice way to lay out this repository please open an issue. diff --git a/dist/index.html b/dist/index.html index 79ea7ce..fefeb57 100644 --- a/dist/index.html +++ b/dist/index.html @@ -107,6 +107,7 @@

Visual Subnet Calculator

  • Mode - Standard
  • Mode - AWS
  • Mode - Azure
  • +
  • Mode - OCI
  • Import / Export
  • diff --git a/dist/js/main.js b/dist/js/main.js index c2d4ed7..93607d3 100644 --- a/dist/js/main.js +++ b/dist/js/main.js @@ -23,6 +23,12 @@ let infoColumnCount = 5 // - Net+2 = Reserved - DNS Mapping // - Net+3 = Reserved - DNS Mapping // - Last = Broadcast Address +// OCI mode: +// - Smallest subnet: /30 +// - Three reserved addresses per subnet: +// - Net+0 = Network Address +// - Net+1 = OCI Reserved - Default Gateway Address +// - Last = Broadcast Address let noteTimeout; let operatingMode = 'Standard' let previousOperatingMode = 'Standard' @@ -34,12 +40,14 @@ const netsizePatterns = { Standard: '^([12]?[0-9]|3[0-2])$', AZURE: '^([12]?[0-9])$', AWS: '^(1?[0-9]|2[0-8])$', + OCI: '^([12]?[0-9]|{30})$', }; const minSubnetSizes = { Standard: 32, AZURE: 29, AWS: 28, + OCI: 30, }; $('input#network').on('paste', function (e) { @@ -123,6 +131,15 @@ $('#dropdown_aws').click(function() { } }); +$('#dropdown_oci').click(function() { + previousOperatingMode = operatingMode; + operatingMode = 'OCI'; + + if(!switchMode(operatingMode)) { + operatingMode = previousOperatingMode; + $('#dropdown_'+ operatingMode.toLowerCase()).addClass('active'); + } +}); $('#importBtn').on('click', function() { importConfig(JSON.parse($('#importExportArea').val())) @@ -415,7 +432,21 @@ function subnet_usable_first(network, netSize, operatingMode) { // AWS reserves 3 additional IPs // https://learn.microsoft.com/en-us/azure/virtual-network/virtual-networks-faq#are-there-any-restrictions-on-using-ip-addresses-within-these-subnets // Azure reserves 3 additional IPs - return network + (operatingMode == 'Standard' ? 1 : 4); + // https://docs.oracle.com/en-us/iaas/Content/Network/Concepts/overview.htm#Reserved__reserved_subnet + // OCI reserves 2 additional IPs + //return network + (operatingMode == 'Standard' ? 1 : 4); + switch (operatingMode) { + case 'AWS': + case 'AZURE': + return network + 4; + break; + case 'OCI': + return network + 2; + break; + default: + return network + 1; + break; + } } else { return network; } @@ -587,6 +618,9 @@ function mutate_subnet_map(verb, network, subnetTree, propValue = '') { case 'AZURE': var modal_error_message = 'The minimum IPv4 subnet size for Azure is /' + minSubnetSizes[operatingMode] + '.

    More Information:
    Azure Virtual Network FAQ > How small and how large can virtual networks and subnets be?' break; + case 'OCI': + var modal_error_message = 'The minimum IPv4 subnet size for OCI is /' + minSubnetSizes[operatingMode] + '.

    More Information:
    Infrastructure Services>Networking>Networking Overview>Three IP Addresses in Each Subnet' + break; default: var modal_error_message = 'The minimum size for an IPv4 subnet is /' + minSubnetSizes[operatingMode] + '.

    More Information:
    Wikipedia - Classless Inter-Domain Routing' break; @@ -635,6 +669,9 @@ function switchMode(operatingMode) { case 'AZURE': var validate_error_message = 'Azure Mode - Smallest size is /' + minSubnetSizes[operatingMode] break; + case 'OCI': + var validate_error_message = 'OCI Mode - Smallest size is /' + minSubnetSizes[operatingMode] + break; default: var validate_error_message = 'Smallest size is /' + minSubnetSizes[operatingMode] break; @@ -651,7 +688,7 @@ function switchMode(operatingMode) { } }); // Remove active class from all buttons if needed - $('#dropdown_standard, #dropdown_azure, #dropdown_aws').removeClass('active'); + $('#dropdown_standard, #dropdown_azure, #dropdown_aws, #dropdown_oci').removeClass('active'); $('#dropdown_' + operatingMode.toLowerCase()).addClass('active'); isSwitched = true; } else { @@ -662,6 +699,9 @@ function switchMode(operatingMode) { case 'AZURE': var modal_error_message = 'One or more subnets are smaller than the minimum allowed for Azure.
    The smallest size allowed is /' + minSubnetSizes[operatingMode] + '.
    See: Azure Virtual Network FAQ > How small and how large can virtual networks and subnets be?' break; + case 'OCI': + var modal_error_message = 'One or more subnets are smaller than the minimum allowed for OCI.
    The smallest size allowed is /' + minSubnetSizes[operatingMode] + '.
    See: Infrastructure Services>Networking>Networking Overview>Three IP Addresses in Each Subnet' + break; default: var validate_error_message = 'Unknown Error' break; @@ -707,6 +747,9 @@ function set_usable_ips_title(operatingMode) { case 'AZURE': $('#useableHeader').html('Usable IPs (Azure)') break; + case 'OCI': + $('#useableHeader').html('Usable IPs (OCI)') + break; default: $('#useableHeader').html('Usable IPs') break; diff --git a/src/tests/import-export.spec.ts b/src/tests/import-export.spec.ts index b3a1207..34dd46f 100644 --- a/src/tests/import-export.spec.ts +++ b/src/tests/import-export.spec.ts @@ -29,6 +29,16 @@ test('Default (Azure) Export Content', async ({ page }) => { await page.getByLabel('Import/Export', { exact: true }).getByText('Close').click(); }); +test('Default (OCI) Export Content', async ({ page }) => { + await page.goto('/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - OCI' }).click(); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Import / Export' }).click(); + await expect(page.getByLabel('Import/Export Content')).toHaveValue('{\n "config_version": "2",\n "operating_mode": "OCI",\n "base_network": "10.0.0.0/16",\n "subnets": {\n "10.0.0.0/16": {}\n }\n}'); + //await page.getByLabel('Import/Export', { exact: true }).getByText('Close').click(); +}); + test('Import 192.168.0.0/24', async ({ page }) => { await page.goto('/'); await page.getByRole('button', { name: 'Tools' }).click(); diff --git a/src/tests/subnet-basic.spec.ts b/src/tests/subnet-basic.spec.ts index bcdea33..e638238 100644 --- a/src/tests/subnet-basic.spec.ts +++ b/src/tests/subnet-basic.spec.ts @@ -125,6 +125,13 @@ test('Usable IPs - Azure', async ({ page }) => { await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Usable IPs')).toContainText('10.0.0.4 - 10.0.255.254'); }); +test('Usable IPs - OCI', async ({ page }) => { + await page.goto('/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - OCI' }).click(); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Usable IPs')).toContainText('10.0.0.2 - 10.0.255.254'); +}); + test('Note Splitting', async ({ page }) => { await page.goto('/'); await page.getByLabel('Note Split/Join').click(); diff --git a/src/tests/ui-error-handling.spec.ts b/src/tests/ui-error-handling.spec.ts index a24c345..ddb7254 100644 --- a/src/tests/ui-error-handling.spec.ts +++ b/src/tests/ui-error-handling.spec.ts @@ -74,3 +74,15 @@ test('Subnet Too Small for Azure Mode', async ({ page }) => { await expect(page.getByText('Azure Mode - Smallest size is /29')).toBeVisible(); }); +test('Subnet Too Small for OCI Mode', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - OCI' }).click(); + await page.getByLabel('Network Size').click(); + await page.getByLabel('Network Size').fill('31'); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.locator('#notifyModalLabel')).toContainText('Warning!'); + await expect(page.locator('#notifyModalDescription')).toContainText('Please correct the errors in the form!'); + await expect(page.getByText('OCI Mode - Smallest size is /30')).toBeVisible(); +}); diff --git a/src/tests/ui-usage.spec.ts b/src/tests/ui-usage.spec.ts index 76af731..7c862f8 100644 --- a/src/tests/ui-usage.spec.ts +++ b/src/tests/ui-usage.spec.ts @@ -76,6 +76,15 @@ test('Table Header Azure Mode', async ({ page }) => { await expect(page.getByText('Azure reserves 5 addresses in')).toBeVisible(); }); +test('Table Header OCI Mode', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - OCI' }).click(); + await expect(page.getByRole('cell', { name: 'Usable IPs', exact: true })).toContainText('Usable IPs (OCI)'); + await page.getByRole('link', { name: 'OCI' }).hover() + await expect(page.getByText('OCI reserves 3 addresses in')).toBeVisible(); +}); test('Table Header AWS then Standard', async ({ page }) => { await page.goto('/');