Post

How to resolve FQDN to an IP address in Aria Orchestrator

Let’s see how we can use the built-in System.resolveHostName() method in vRO to resolve the FQDN to the IP address.

Implementation

We’re going to create a new class with a few methods:

  1. waitForDNSResolve
  2. isValidIPv4
  3. throwError

Let’s say we created a new A record in the DNS server and must wait until the address is resolved to continue the workflow. It may take some time until the IP is resolved. Therefore, we’ll need to wait and try a few times. If, after a few retries, the IP is still not resolvable, we’ll throw an error.

waitForDNSResolve()

Here, a function waitForDNSResolve() accepts a host FQDN as a string. The function will try to resolve the FQDN 20 times and wait for 60 seconds between retries.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public waitForDNSResolve ( hostFqdn: string ): void {
        const maxAttempts = 20;
        const sleepTime = 60000; // Sleep for a minute

        for ( let i = 0; i < maxAttempts; i++ ) {
            try {
                const ip = System.resolveHostName( hostFqdn );
                if ( ip && this.isValidIPv4( ip ) ) {
                    return; // DNS resolved successfully
                }
            } catch ( error ) {
                System.error( `Error resolving ${ hostFqdn }: ${ error.message }` );
            }
            System.log( `Not yet resolvable. Sleeping for ${ sleepTime / 1000 } seconds` );
            System.sleep( sleepTime )
        }
        System.warn( `DNS resolution failed after ${ maxAttempts } attempts.` );
    }

isValidIPv4()

Once the FQDN is resolved, we want to make sure that the return IP address is a valid IP. For that, we have a function isValidIPv4(), which accepts the IP as a string, tests it against a regular expression, and returns a boolean if the address is valid.

1
2
3
4
    public isValidIPv4 ( ip: string ): boolean {
        const ipv4Regex = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/;
        return ipv4Regex.test( ip )
    }

throwError()

If the result of isValidIPv4() is true, the main function waitForDNSResolve() will return. But if after 20 retries, the FQDN is still not resolved, we will throw an error with a simple function called throwError() .

1
2
3
    public throwError ( errorMessage: string ): never {
        throw new Error( errorMessage )
    }

The final code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
export class SampleClass {
    public throwError ( errorMessage: string ): never {
        throw new Error( errorMessage )
    }

    public isValidIPv4 ( ip: string ): boolean {
        const ipv4Regex = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/;
        return ipv4Regex.test( ip )
    }

    public waitForDNSResolve ( hostFqdn: string ) {
        const maxAttempts = 20;
        const sleepTime = 60000; // Sleep for a minute

        for ( let i = 0; i < maxAttempts; i++ ) {
            try {
                const ip = System.resolveHostName( hostFqdn );
                if ( ip && this.isValidIPv4( ip ) ) {
                    return; // DNS resolved successfully
                }
            } catch ( error ) {
                System.error( `Error resolving ${ hostFqdn }: ${ error.message }` );
            }
            System.log( `Not yet resolvable. Sleeping for ${ sleepTime / 1000 } seconds` );
            System.sleep( sleepTime )
        }
        System.warn( `DNS resolution failed after ${ maxAttempts } attempts.` );
    }
}

Unit Test

Creating a unit test for a code is always a good idea. Let’s develop tests for our functions with Jasmine, which is built into the vRBT. The code is pretty self-explanatory.

Testing isValidIPv4()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
describe( 'isValidIPv4', () => {
    let fakeIp;

    beforeEach( () => {
    } );

    it( 'should return true for a valid IP address', () => {
        fakeIp = '192.168.1.10';
        const result = func.isValidIPv4( fakeIp );

        expect( result ).toBe( true );
    } );

    it( 'should return false for an invalid IP address', () => {
        fakeIp = '256.0.0.1'; // Invalid IP
        const result = func.isValidIPv4( fakeIp );

        expect( result ).toBe( false );
    } );
} );

Testing waitForDNSResolve()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
describe( 'waitForDNSResolve', () => {
    let fakeHostFqdn;
    let fakeIp;

    beforeEach( () => {
        fakeIp = '192.168.1.10';
        fakeHostFqdn = 'example.com';

        spyOn( System, 'error' );
        spyOn( System, 'log' );
        spyOn( System, 'warn' );
    } );

    it( 'should resolve DNS successfully', () => {
        spyOn( System, 'resolveHostName' ).and.returnValue( fakeIp );
        func.waitForDNSResolve( fakeHostFqdn );

        expect( System.resolveHostName ).toHaveBeenCalledWith( fakeHostFqdn );
    } );

    it( 'should log an error if DNS resolution fails', () => {
        const errorMessage = 'DNS resolution failed';
        spyOn( System, 'resolveHostName' ).and.throwError( errorMessage );
        func.waitForDNSResolve( fakeHostFqdn );

        expect( System.resolveHostName ).toHaveBeenCalledWith( fakeHostFqdn );
        expect( System.error ).toHaveBeenCalledWith( `Error resolving ${ fakeHostFqdn }: ${ errorMessage }` );
    } );

    it( 'should log a warning after max attempts', () => {
        spyOn( System, 'sleep' );
        func.waitForDNSResolve( fakeHostFqdn );

        expect( System.sleep ).toHaveBeenCalledTimes( 20 );
        expect( System.warn ).toHaveBeenCalledWith( `DNS resolution failed after 20 attempts.` );
    } );
} );

Source code

The source code can be found here

This post is licensed under CC BY 4.0 by the author.