From 8a771f3ea0dbd660c6403bfd7bfabc1153fd5cab Mon Sep 17 00:00:00 2001
From: Qin Zhao <q.zhao@f5.com>
Date: Thu, 26 Sep 2019 16:20:05 +0800
Subject: [PATCH] Support force delete ADC resource

---
 app/waf/src/controllers/adc.controller.ts     | 11 ++++-
 app/waf/src/controllers/schema.ts             |  9 ++++
 .../acceptance/adc.controller.acceptance.ts   | 41 ++++++++++++++++++-
 3 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/app/waf/src/controllers/adc.controller.ts b/app/waf/src/controllers/adc.controller.ts
index 5e280ce43..7c6b4a231 100644
--- a/app/waf/src/controllers/adc.controller.ts
+++ b/app/waf/src/controllers/adc.controller.ts
@@ -385,11 +385,20 @@ export class AdcController extends BaseController {
   })
   async deleteById(
     @param(Schema.pathParameter('adcId', 'ADC resource ID')) id: string,
+    @param(
+      Schema.queryParameter('force', 'Force delete ADC resource', 'boolean'),
+    )
+    force: boolean = false,
   ): Promise<void> {
     let adc = await this.adcRepository.findById(id, undefined, {
       tenantId: await this.tenantId,
     });
 
+    if (force) {
+      await this.adcRepository.deleteById(id);
+      return;
+    }
+
     if (adc.type === 'HW') {
       if (!(await this.untrustAdc(adc)))
         throw new HttpErrors.UnprocessableEntity('Fail to untrust device');
@@ -706,7 +715,7 @@ export class AdcController extends BaseController {
     return userDataB64Encoded;
   }
 
-  private async deleteOn(adc: Adc, addon: AddonReqValues): Promise<void> {
+  public async deleteOn(adc: Adc, addon: AddonReqValues): Promise<void> {
     let reclaimFuncs: {[key: string]: Function} = {
       license: async () => {
         let doMgr = await OnboardingManager.instanlize(
diff --git a/app/waf/src/controllers/schema.ts b/app/waf/src/controllers/schema.ts
index 3395b8d67..083e06395 100644
--- a/app/waf/src/controllers/schema.ts
+++ b/app/waf/src/controllers/schema.ts
@@ -222,6 +222,15 @@ export class Schema {
     return buildParameterSchema(name, 'path', true, 'string', '', desc);
   }
 
+  static queryParameter(
+    name: string,
+    desc: string,
+    type: string,
+    format?: string,
+  ): ParameterObject {
+    return buildParameterSchema(name, 'query', false, type, format || '', desc);
+  }
+
   static createRequest(entity: typeof Entity, desc: string): object {
     let props = buildProperties(entity);
     return buildRequestSchema(
diff --git a/app/waf/test/acceptance/adc.controller.acceptance.ts b/app/waf/test/acceptance/adc.controller.acceptance.ts
index 96c46b097..8ae7b20c6 100644
--- a/app/waf/test/acceptance/adc.controller.acceptance.ts
+++ b/app/waf/test/acceptance/adc.controller.acceptance.ts
@@ -2103,7 +2103,7 @@ describe('AdcController test', () => {
     });
   });
 
-  it('post ' + prefix + '/adcs/{adcId}: delete done', async () => {
+  it('delete ' + prefix + '/adcs/{adcId}: delete done', async () => {
     LetResponseWith({
       bigip_get_mgmt_tm_sys_license: StubResponses.bigipNoLicense200,
     });
@@ -2134,6 +2134,45 @@ describe('AdcController test', () => {
     expect(resp.status).equal(404);
   });
 
+  it('delete ' + prefix + '/adcs/{adcId}: force delete', async () => {
+    let adc = await givenAdcData(wafapp, {
+      type: 'VE',
+      status: 'ACTIVE',
+    });
+
+    let stub = sinon.stub(controller, 'deleteOn');
+
+    await client
+      .del(`${prefix}/adcs/${adc.id}?force=true`)
+      .set('X-Auth-Token', ExpectedData.userToken)
+      .set('tenant-id', ExpectedData.tenantId)
+      .expect(204);
+
+    await client
+      .get(`${prefix}/adcs/${adc.id}`)
+      .set('X-Auth-Token', ExpectedData.userToken)
+      .set('tenant-id', ExpectedData.tenantId)
+      .expect(404);
+
+    expect(!stub.called);
+    stub.restore();
+  });
+
+  it('delete ' + prefix + '/adcs/{adcId}: wrong force parameter', async () => {
+    let adc = await givenAdcData(wafapp, {
+      type: 'VE',
+      status: 'ACTIVE',
+    });
+
+    let resp = await client
+      .del(`${prefix}/adcs/${adc.id}?force=abc`)
+      .set('X-Auth-Token', ExpectedData.userToken)
+      .set('tenant-id', ExpectedData.tenantId)
+      .expect(400);
+
+    expect(resp.body.error.code).equal('INVALID_PARAMETER_VALUE');
+  });
+
   //TODO: the timeout can only be tested through unit test?
   //The following test case leads all tests fail.
   // it(