Skip to content

Commit

Permalink
Enable auto-delete option for virtual address for Common partition
Browse files Browse the repository at this point in the history
  • Loading branch information
mohan-f5 authored and Nagaraju-F5 committed Dec 16, 2024
1 parent abc5b89 commit ecf2682
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/lib/map_as3.js
Original file line number Diff line number Diff line change
Expand Up @@ -2308,6 +2308,7 @@ const translate = {
if (itemCopy.serverScope === undefined) {
itemCopy.serverScope = 'any';
}
itemCopy.autoDelete = (itemCopy.autoDelete === undefined) ? 'true' : itemCopy.autoDelete;
const taggedId = `Service_Address-${itemId}`;
return { configs: [normalize.actionableMcp(context, itemCopy, 'ltm virtual-address', util.mcpPath(tenantId, newAppId, taggedId))] };
},
Expand Down
38 changes: 37 additions & 1 deletion src/lib/postValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,27 @@ class postValidator {
return promise.then(() => tcpProfile(context, declaration))
.then(() => sslProfile(context, declaration))
.then(() => protocolInspectionProfile(context, declaration))
.then(() => service(context, declaration));
.then(() => service(context, declaration))
.then(() => virtualAddressInspect(declaration));
}

return promise;
}
}

function virtualAddressInspect(declaration) {
const virtualAddressProfiles = findVirtualAddressinTenants(declaration, 'Service_Address');
let err;

if (virtualAddressProfiles.some((profile) => profile.autoDelete === false)) {
err = new Error('Disabling auto-delete for service addresses in non-common tenants is not supported.');
err.statusCode = 422;
return Promise.reject(err);
}

return Promise.resolve();
}

function protocolInspectionProfile(context, declaration) {
const profiles = findItems(declaration, 'Protocol_Inspection_Profile');
let err;
Expand Down Expand Up @@ -150,6 +164,28 @@ function findItems(declaration, itemName) {
return items;
}

function findVirtualAddressinTenants(declaration, itemName) {
const items = [];
const decKeys = Object.keys(declaration);
decKeys.forEach((decKey) => {
const tenant = declaration[decKey];
if (declarationUtil.isTenant(tenant) && decKey !== 'Common') {
Object.keys(tenant).forEach((tenKey) => {
const application = tenant[tenKey];
if (declarationUtil.isApplication(application)) {
Object.keys(application).forEach((appKey) => {
const item = application[appKey];
if (typeof item === 'object' && item.class === itemName) {
items.push(item);
}
});
}
});
}
});
return items;
}

function validatePathLengths(declaration) {
let err;
const decKeys = Object.keys(declaration);
Expand Down
3 changes: 2 additions & 1 deletion src/lib/properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -1303,7 +1303,8 @@
{ "id":"route-advertisement" },
{ "id":"spanning", "truth": "enabled", "falsehood": "disabled", "altId": "spanningEnabled" },
{ "id":"server-scope" },
{ "id":"traffic-group" }
{ "id":"traffic-group" },
{ "id":"auto-delete" , "truth": "true", "falsehood": "false" }
],
"ltm cipher rule": [
{ "id":"cipher" },
Expand Down
6 changes: 6 additions & 0 deletions src/schema/latest/core-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2618,6 +2618,12 @@
"description": "Specifies the traffic group which the Service_Address belongs.",
"type": "string",
"default": "default"
},
"autoDelete": {
"title": "Auto Delete",
"description": "If this is true, MCPD deletes the virtual address if it is not linked to any virtual. This option applies only to the Common Tenant.",
"type": "boolean",
"default": true
}
},
"dependencies": {
Expand Down
99 changes: 99 additions & 0 deletions test/integration/bigip/misc/serviceAddress.js
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,55 @@ describe('serviceAddress', function () {
.then(() => deleteBigipItems(bigipItems)));
});

it('should not be thrown an error if the Service Address autoDelete field is enabled on non-common partitions', () => {
const decl = {
class: 'ADC',
schemaVersion: '3.0.0',
tenant: {
class: 'Tenant',
app: {
class: 'Application',
vaddr: {
class: 'Service_Address',
virtualAddress: '10.0.1.2',
autoDelete: true
}
}
}
};

return Promise.resolve()
.then(() => postDeclaration(decl, { declarationIndex: 0 }))
.then((response) => {
assert.strictEqual(response.results[0].code, 200);
}).finally(() => deleteDeclaration());
});

it('should be thrown an error if the Service Address autoDelete field is disabled on non-common partitions.', () => {
const decl = {
class: 'ADC',
schemaVersion: '3.0.0',
tenant: {
class: 'Tenant',
app: {
class: 'Application',
vaddr: {
class: 'Service_Address',
virtualAddress: '10.0.1.2',
autoDelete: false
}
}
}
};

return Promise.resolve()
.then(() => postDeclaration(decl, { declarationIndex: 0 }))
.then((response) => {
assert.strictEqual(response.results[0].code, 422);
assert.strictEqual(response.results[0].message, 'Disabling auto-delete for service addresses in non-common tenants is not supported.');
});
});

describe('per-app', () => {
let Shared;
let serviceApp;
Expand Down Expand Up @@ -483,6 +532,56 @@ describe('serviceAddress', function () {
'virtual-address should have been deleted'
));
});

it('should delete the Service_Address in Common partition using autoDelete flag', () => {
const perAppCommonPath = '/mgmt/shared/appsvcs/declare/Common/applications';
const perAppTenantPath = '/mgmt/shared/appsvcs/declare/Tenant/applications';
Shared.ServiceAddress.autoDelete = true;
serviceApp.Service.virtualAddresses.push({ use: '/Common/Shared/ServiceAddress' });
return Promise.resolve()
.then(() => postDeclaration({ schemaVersion: '3.50', Shared }, { declarationIndex: 0 }, undefined, perAppCommonPath))
.then((response) => {
assert.strictEqual(response.results[0].code, 200);
})
.then(() => getPath('/mgmt/tm/ltm/virtual-address/~Common~Shared~ServiceAddress'))
.then(() => postDeclaration({ schemaVersion: '3.50', serviceApp }, { declarationIndex: 1 }, undefined, perAppTenantPath))
.then((response) => {
assert.strictEqual(response.results[0].code, 200);
})
// Virtual-address should be removed from /Common/Shared once associated app is removed
.then(() => deleteDeclaration(undefined, { path: `${perAppTenantPath}/serviceApp?async=true`, sendDelete: true }))
.then((response) => {
assert.strictEqual(response.results[0].code, 200);
})
.then(() => assert.isRejected(
getPath('/mgmt/tm/ltm/virtual-address/~Common~Shared~ServiceAddress'),
/The requested Virtual Address \(\/Common\/Shared\/ServiceAddress\) was not found/,
'virtual-address should have been deleted'
));
});

it('should not delete the Service_Address in Common partition using autoDelete flag', () => {
const perAppCommonPath = '/mgmt/shared/appsvcs/declare/Common/applications';
const perAppTenantPath = '/mgmt/shared/appsvcs/declare/Tenant/applications';
Shared.ServiceAddress.autoDelete = false;
serviceApp.Service.virtualAddresses.push({ use: '/Common/Shared/ServiceAddress' });
return Promise.resolve()
.then(() => postDeclaration({ schemaVersion: '3.50', Shared }, { declarationIndex: 0 }, undefined, perAppCommonPath))
.then((response) => {
assert.strictEqual(response.results[0].code, 200);
})
.then(() => getPath('/mgmt/tm/ltm/virtual-address/~Common~Shared~ServiceAddress'))
.then(() => postDeclaration({ schemaVersion: '3.50', serviceApp }, { declarationIndex: 1 }, undefined, perAppTenantPath))
.then((response) => {
assert.strictEqual(response.results[0].code, 200);
})
// Virtual-address should not be removed from /Common/Shared once associated app is removed
.then(() => deleteDeclaration(undefined, { path: `${perAppTenantPath}/serviceApp?async=true`, sendDelete: true }))
.then((response) => {
assert.strictEqual(response.results[0].code, 200);
})
.then(() => getPath('/mgmt/tm/ltm/virtual-address/~Common~Shared~ServiceAddress'));
});
});

describe('virtualAddress with RouteDomain ID', () => {
Expand Down
53 changes: 51 additions & 2 deletions test/unit/lib/map_as3.js
Original file line number Diff line number Diff line change
Expand Up @@ -2758,6 +2758,53 @@ describe('map_as3', () => {
const results = translate.Service_Address(defaultContext, 'foo', 'bar', '10.10.0.11', item, declaration);
assert.strictEqual(results.configs[0].path, '/foo/Service_Address-10.10.0.11');
});

it('should check autoDelete flag is true by detaul in Service Address', () => {
const item = {
arp: true,
icmpEcho: 'enable',
spanning: false,
shareAddresses: false,
virtualAddress: '10.10.0.12',
serverScope: 'all'
};

const results = translate.Service_Address(defaultContext, 'foo', 'bar', '10.10.0.12', item, declaration);
assert.strictEqual(results.configs[0].path, '/foo/Service_Address-10.10.0.12');
assert.strictEqual(results.configs[0].properties['auto-delete'], 'true');
});

it('should check autoDelete flag value is true in Service Address', () => {
const item = {
arp: true,
icmpEcho: 'enable',
spanning: false,
shareAddresses: false,
virtualAddress: '10.10.0.12',
serverScope: 'all',
autoDelete: true
};

const results = translate.Service_Address(defaultContext, 'foo', 'bar', '10.10.0.12', item, declaration);
assert.strictEqual(results.configs[0].path, '/foo/Service_Address-10.10.0.12');
assert.strictEqual(results.configs[0].properties['auto-delete'], 'true');
});

it('should check autoDelete flag value is false in Service Address', () => {
const item = {
arp: true,
icmpEcho: 'enable',
spanning: false,
shareAddresses: false,
virtualAddress: '10.10.0.12',
serverScope: 'all',
autoDelete: false
};

const results = translate.Service_Address(defaultContext, 'foo', 'bar', '10.10.0.12', item, declaration);
assert.strictEqual(results.configs[0].path, '/foo/Service_Address-10.10.0.12');
assert.strictEqual(results.configs[0].properties['auto-delete'], 'false');
});
});
});

Expand Down Expand Up @@ -6163,7 +6210,8 @@ describe('map_as3', () => {
'route-advertisement': 'disabled',
spanning: 'disabled',
'traffic-group': 'default',
'server-scope': 'any'
'server-scope': 'any',
'auto-delete': 'true'
},
ignore: []
},
Expand Down Expand Up @@ -12786,7 +12834,8 @@ describe('map_as3', () => {
'route-advertisement': 'disabled',
spanning: 'disabled',
'traffic-group': 'default',
'server-scope': 'any'
'server-scope': 'any',
'auto-delete': 'true'
};

const result = translate.Service_Forwarding(defaultContext, 'tenantId', 'appId', 'itemId', item);
Expand Down
65 changes: 65 additions & 0 deletions test/unit/lib/postValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,5 +426,70 @@ describe('postValidator', () => {
);
});
});

describe('AutoDelete', () => {
const declaration = {
class: 'ADC',
schemaVersion: '3.50.0',
Common: {
class: 'Tenant',
Shared: {
class: 'Application',
template: 'shared',
'x_service-address_any': {
class: 'Service_Address',
virtualAddress: '0.0.0.0',
icmpEcho: 'disable',
arpEnabled: false,
autoDelete: true
}
}
}
};

const declaration1 = {
class: 'ADC',
schemaVersion: '3.50.0',
testTenant: {
class: 'Tenant',
testApp: {
class: 'Application',
template: 'shared',
testObj: {
class: 'Service_Address',
virtualAddress: '0.0.0.0',
icmpEcho: 'disable',
arpEnabled: false,
autoDelete: true
}
}
}
};

it('should be valid true for Common partion', () => {
defaultContext.target.tmosVersion = '16.1';
return assert.isFulfilled(PostValidator.validate(defaultContext, declaration));
});

it('should be valid false for Common partion', () => {
defaultContext.target.tmosVersion = '16.1';
declaration.Common.Shared['x_service-address_any'].autoDelete = false;
return assert.isFulfilled(PostValidator.validate(defaultContext, declaration));
});

it('should be valid true for non-Common partion', () => {
defaultContext.target.tmosVersion = '16.1';
return assert.isFulfilled(PostValidator.validate(defaultContext, declaration1));
});

it('should be invalid false for non-Common partion', () => {
defaultContext.target.tmosVersion = '16.1';
declaration1.testTenant.testApp.testObj.autoDelete = false;
return assert.isRejected(
PostValidator.validate(defaultContext, declaration1),
'Disabling auto-delete for service addresses in non-common tenants is not supported.'
);
});
});
});
});

0 comments on commit ecf2682

Please sign in to comment.