Skip to content

Commit

Permalink
Change polling to sched task, added future date, license year update
Browse files Browse the repository at this point in the history
  • Loading branch information
ladamato committed Mar 25, 2021
1 parent df597e3 commit 6ac6f59
Show file tree
Hide file tree
Showing 18 changed files with 119 additions and 72 deletions.
54 changes: 27 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# XL Release UCD Plugin

[![Build Status][xlr-ucd-plugin-travis-image]][xlr-ucd-plugin-travis-url]
[![Codacy Badge][xlr-ucd-plugin-codacy-image] ][xlr-ucd-plugin-codacy-url]
[![Code Climate][xlr-ucd-plugin-code-climate-image] ][xlr-ucd-plugin-code-climate-url]
[![License: MIT][xlr-ucd-plugin-license-image] ][xlr-ucd-plugin-license-url]
Expand All @@ -20,7 +19,13 @@ This plugin offers an interface from XL Release to Urban Code Deploy Server.

## Requirements

* XL Release** 9.0.0+
Changes introduced in version 2.0.0 -
1. Polling for tasks that retrieve Status information has been replaced with the Release Schedule Task mechanism. This allows tasks to resume even if Release is rebooted. If your template includes polling parameters, you will see an alert indicator in your task, but the task will still work without changes.
2. It is now possible to set a UCD Application Process Request for a future date/time deployment.

## Requirements

* XL Release** 9.8.0+
* This plugin has been tested with XL Release 9.8.0 and UCD 7.1.0

## Installation
Expand All @@ -39,7 +44,8 @@ The List System Configuration task will list the system attributes as name value

### Application Process Request

The Application Process Request task will invoke an Application Process Request in UCD for the given Application, Application Process, Environment and Versions (as defined in UCD). The Application Process Request ID is retrieved for display or stored in an XL Release variable.
The Application Process Request task will invoke an Application Process Request in UCD for the given Application, Application Process, Environment and Versions (as defined in UCD). If Future Date and Time is set, UDC will put the request into a pending state until that time. The Date/Time string must be in the format yyyy-mm-dd HH:mm ,use a 24 hour clock for hours. Example: 2021-03-23 13:30 .
The Application Process Request ID is retrieved for display or stored in an XL Release variable.

![app_process_request](images/appProcessRequest.png)

Expand All @@ -51,7 +57,7 @@ Given an Application Process Request ID, this task will poll UCD for the status

### Synchronous Application Process

The Synchronous Application Process task will invoke a UCD Application Process Request and then immediately poll for the status of that request. The Request ID, Request Status and Request Result are output.
The Synchronous Application Process task will invoke a UCD Application Process Request and then immediately poll for the status of that request. If Future Date and Time is set, UDC will put the request into a pending state until that time. The Date/Time string must be in the format yyyy-mm-dd HH:mm ,use a 24 hour clock for hours. Example: 2021-03-23 13:30 . The Request ID, Request Status and Request Result are output.

![sync_process_request](images/synchronousAppProcess.png)

Expand All @@ -67,30 +73,19 @@ Build and package the plugins with...
./gradlew assemble
```

### To run integration tests

1. Clone this git project to your local dev environment
2. You will need to have Docker and Docker Compose installed.
3. The XL-Release docker image uses the community trial license
4. Open a terminal in the root of the xlr-ucd-plugin project and run the following gradle task

```bash
./gradlew clean integrationTest
```

The test will set up a temporary xlr/ucd testbed using docker. After testing is complete, the test docker containers are stopped and removed.

### To run demo or dev version (set up docker containers for both XLR and UCD platform)

NOTE:

1. For requirements, see the 'To run integration tests' above.
2. You will need to be able to run a bash script
3. You will need to have [curl](https://curl.haxx.se/) and [jq](https://stedolan.github.io/jq/) installed
4. XL Release will run on the [localhost port 15516](http://localhost:15516/).
5. The XL Release username / password is admin / admin.
6. The UCD Server runs on the [localhost port 8443](https://localhost:8443/)
7. The UCD username / password is admin / admin
1. Clone this git project to your local dev environment
2. You will need to have Docker and Docker Compose installed.
3. The XL-Release docker image uses the community trial license
4. You will need to be able to run a bash script
5. You will need to have [curl](https://curl.haxx.se/) and [jq](https://stedolan.github.io/jq/) installed
6. XL Release will run on the [localhost port 15516](http://localhost:15516/).
7. The XL Release username / password is admin / admin.
8. The UCD Server runs on the [localhost port 8443](https://localhost:8443/)
9. The UCD username / password is admin / admin

* Before running the demo, be sure to create the plugin by opening a terminal, cd into the plugin source code directory, and run

Expand All @@ -104,7 +99,13 @@ NOTE:
docker-compose up
```

* After XLR and the UCD Platform starts up, open a terminal in the directory src/test/resources/docker/initialize and run the initialize_demo.sh script. This will populate both XLR and the UCD Server with the demo data. You can then log into XLR, create and then run a release based upon the imported template name 'ucdTest'.
* After XLR and the UCD Platform starts up, open a terminal in the directory src/test/resources/docker/initialize and run

```bash
./initialize_demo.sh
```

* This will populate both XLR and the UCD Server with the demo data. You can then log into XLR, create and then run a release based upon the imported template name 'ucdTest'.

* To shut down and remove the docker containers - in a terminal, cd to the src/test/resources/docker directory, and run

Expand All @@ -116,8 +117,7 @@ docker-compose down

+ [UCD REST api](https://www.ibm.com/support/knowledgecenter/SS4GSP_7.1.0/com.ibm.udeploy.reference.doc/topics/rest_api_ref_commands.html)

[xlr-ucd-plugin-travis-image]: https://travis-ci.org/xebialabs-community/xlr-ucd-plugin.svg?branch=master
[xlr-ucd-plugin-travis-url]: https://travis-ci.org/xebialabs-community/xlr-ucd-plugin

[xlr-ucd-plugin-codacy-image]: https://api.codacy.com/project/badge/Grade/da9c2f00342c40ad8efc7fbd1aaec063
[xlr-ucd-plugin-codacy-url]: https://www.codacy.com/app/joris-dewinne/xlr-ucd-plugin
[xlr-ucd-plugin-code-climate-image]: https://codeclimate.com/github/xebialabs-community/xlr-ucd-plugin/badges/gpa.svg
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
id 'nebula.release' version '13.0.0'
}

version='1.5.0'
version='2.0.0'

apply plugin: 'java'
apply plugin: 'idea'
Expand Down
Binary file modified images/appProcessRequest.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/status.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/synchronousAppProcess.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 8 additions & 11 deletions src/main/resources/synthetic.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<!--
Copyright 2020 XEBIALABS
Copyright 2021 XEBIALABS
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Expand Down Expand Up @@ -51,18 +51,19 @@
<property name="properties" category="input" label="Properties"
description="Map containing the properties for the application process." kind="map_string_string"
required="false"/>
<property name="scheduleDate" category="input" label="(Optional) Future Date and Time to Schedule Process "
description="You can optionally schedule the application process for a future start. Use a 24 hour clock for hours. Format: yyyy-mm-
dd HH:mm Example: 2021-03-23 13:30 This string will be interpreted by your UCD server so be certain to consider that server's time zone." required="false"/>
<!-- Outputs -->
<property name="requestId" category="output" label="Request Id"
description="The request id for further status retrieval" kind="string"/>
</type>

<type type="ucd.SynchronousApplicationProcessRequest" extends="ucd.ApplicationProcessRequest">
<!-- Input -->
<property name="pollingInterval" category="input" default="10" required="true" kind="integer"
description="Polling interval in seconds to check task status."/>
<property name="numberOfPollingTrials" category="input" default="0" label="Polling Retry Count" required="true"
kind="integer" description="Number of times to retry check for task status, 0 means indefinite."/>

<!-- Inputs -->
<property name="scheduleDate" category="input" label="(Optional) Future Date and Time to Schedule Process "
description="You can optionally schedule the application process for a future start. Use a 24 hour clock for hours. Format: yyyy-mm-
dd HH:mm Example: 2021-03-23 13:30 This string will be interpreted by your UCD server so be certain to consider that server's time zone." required="false"/>
<!-- Outputs -->
<property name="requestStatus" category="output" label="Request Status" description="The request status"
kind="string"/>
Expand All @@ -74,10 +75,6 @@
<!-- Input -->
<property name="requestId" category="input" label="Request Id"
description="The request id for further status retrieval" kind="string"/>
<property name="pollingInterval" category="input" default="10" required="true" kind="integer"
description="Polling interval in seconds to check task status."/>
<property name="numberOfPollingTrials" category="input" default="0" label="Polling Retry Count" required="true"
kind="integer" description="Number of times to retry check for task status, 0 means indefinite."/>

<!-- Outputs -->
<property name="requestStatus" category="output" label="Request Status" description="The request status"
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/ucd/HttpRequest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2020 XEBIALABS
# Copyright 2021 XEBIALABS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/ucd/TestConnection.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2020 XEBIALABS
# Copyright 2021 XEBIALABS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
Expand Down
60 changes: 49 additions & 11 deletions src/main/resources/ucd/UCDClient.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2020 XEBIALABS
# Copyright 2021 XEBIALABS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
Expand All @@ -11,22 +11,31 @@

import json
import time
import logging
import datetime

from ucd.HttpRequest import HttpRequest

logger = logging.getLogger(__name__)

logger.debug("In UCDClient")
# In the case we have a future scheduled ucd_applicationprocessrequest, we don't want to log all those status messages
shouldSupressLogging = False


def check_response(response, message):
if not response.isSuccessful():
raise Exception(message)


class UCD_Client(object):
def __init__(self, http_connection, username=None, password=None, verify=True):
def __init__(self, http_connection, task, username=None, password=None, verify=True):
self.http_request = HttpRequest(http_connection, username, password, verify)
self.task = task

@staticmethod
def create_client(http_connection, username=None, password=None, verify=True):
return UCD_Client(http_connection, username, password, verify)
def create_client(http_connection, task, username=None, password=None, verify=True):
return UCD_Client(http_connection, task, username, password, verify)

def ucd_listsystemconfiguration(self, variables):
system_configuration_endpoint = "/cli/systemConfiguration"
Expand All @@ -39,7 +48,6 @@ def ucd_listsystemconfiguration(self, variables):
variables['systemConfiguration'] = result
return result

# TODO: add 'date' option for scheduled deployments

def ucd_applicationprocessrequest(self, variables):
application_process_request_endpoint = "/cli/applicationProcessRequest/request"
Expand All @@ -49,13 +57,22 @@ def ucd_applicationprocessrequest(self, variables):
body = {'application': variables['application'], 'applicationProcess': variables['applicationProcess'],
'environment': variables['environment'], 'properties': variables['properties'],
'versions': versions_list}
if variables['scheduleDate'] is not None and len(variables['scheduleDate']) > 0:
if self.vaild_dateTime(variables['scheduleDate']):
logger.debug("dateTimeString is valid")
body.update({"date": variables['scheduleDate']})
else:
logger.debug("dateTimeString is Not valid")
raise Exception("Future schedule date is configured but is not in proper format. See field description.")

print "Sending request: [%s]\n" % json.dumps(body)
application_process_request_response = self.http_request.put(application_process_request_endpoint,
json.dumps(body), contentType='application/json')
check_response(application_process_request_response,
"Failed to execute application process request. Server return [%s], with content [%s]" % (
application_process_request_response.status,
application_process_request_response.response))
logger.debug("\napplicationprocessrequest respone was %s\n" % json.loads(application_process_request_response.getResponse()))
result = json.loads(application_process_request_response.getResponse())["requestId"]
variables['requestId'] = result
return result
Expand All @@ -71,6 +88,9 @@ def application_process_request_status(self, request_id):
return json.loads(application_process_request_status_response.getResponse())

def ucd_applicationprocessrequeststatus(self, variables):
#logger.debug("In ucd_applicationprocessrequeststatus")
global shouldSupressLogging

'''
The UCD request returns the following statuses:
CANCELING
Expand Down Expand Up @@ -101,12 +121,22 @@ def ucd_applicationprocessrequeststatus(self, variables):
variables['requestStatus'] = request_response["status"]
variables['requestResult'] = request_response["result"]

# update task status
print ("Received Request Status: [%s] with Request Result: [%s]\n").format(variables['requestStatus'], variables['requestResult'])
# log task status
if variables['requestResult'] is not None and variables['requestResult'] in ('SCHEDULED FOR FUTURE'):
if not shouldSupressLogging:
logger.debug("Received Request Status: Request Id: [%s], Request Status: [%s] with Request Result: [%s], will surpress printout until result change.\n" % (variables['requestId'], variables['requestStatus'], variables['requestResult']))
#print ("Received Request Status: [%s] with Request Result: [%s], will surpress printout until result change.\n" % (variables['requestStatus'], variables['requestResult']))
shouldSupressLogging = True
else:
logger.debug("Received Request Status: Request Id: [%s], Request Status: [%s] with Request Result: [%s].\n" % (variables['requestId'], variables['requestStatus'], variables['requestResult']))
#print ("Received Request Status: [%s] with Request Result: [%s].\n" % (variables['requestStatus'], variables['requestResult']))
# set to false so the print output from application_process_request_status will print at least once
shouldSupressLogging = False


# determine if we're done
if variables['requestStatus'] in ("CLOSED", "FAULTED"):
task.setStatusLine("Result: %s" % variables['requestResult'])
self.task.setStatusLine("Result: %s" % variables['requestResult'])
if variables['requestResult'] not in "SUCCEEDED":
raise Exception("Failed to execute application process request. Status [%s], Result [%s]" % (
variables['requestStatus'], variables['requestResult']))
Expand All @@ -115,10 +145,18 @@ def ucd_applicationprocessrequeststatus(self, variables):

# not done, continue checking
else:
task.setStatusLine("Status: %s" % variables['requestStatus'])
task.schedule('ucd/UCDTask.wait-for-status.py')
self.task.setStatusLine("Status: %s" % variables['requestStatus'])
self.task.schedule('ucd/UCDTask.wait-for-status.py')

def ucd_synchronousapplicationprocessrequest(self, variables):
self.ucd_applicationprocessrequest(variables)
task.schedule('ucd/UCDTask.wait-for-status.py')
self.task.schedule('ucd/UCDTask.wait-for-status.py')

def vaild_dateTime(self, dateTimeString):
logger.debug("In valid_dateTime, dateTimeString = %s" % dateTimeString)
try:
datetime.datetime.strptime(dateTimeString, '%Y-%m-%d %H:%M')
return True
except ValueError:
return False

6 changes: 3 additions & 3 deletions src/main/resources/ucd/UCDClientUtil.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2020 XEBIALABS
# Copyright 2021 XEBIALABS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
Expand All @@ -14,6 +14,6 @@
class UCD_Client_Util(object):

@staticmethod
def create_ucd_client(container, username, password, verifySsl):
client = UCD_Client.create_client(container, username, password, verifySsl)
def create_ucd_client(container, task, username, password, verifySsl):
client = UCD_Client.create_client(container, task, username, password, verifySsl)
return client
4 changes: 2 additions & 2 deletions src/main/resources/ucd/UCDTask.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2020 XEBIALABS
# Copyright 2021 XEBIALABS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
Expand All @@ -11,7 +11,7 @@
from ucd.UCDClientUtil import UCD_Client_Util

verify_ssl = not server['disableSslVerification']
ucd_client = UCD_Client_Util.create_ucd_client(server, username, password, verify_ssl)
ucd_client = UCD_Client_Util.create_ucd_client(server, task, username, password, verify_ssl)
method = str(task.getTaskType()).lower().replace('.', '_')
call = getattr(ucd_client, method)
output = call(locals())
Loading

0 comments on commit 6ac6f59

Please sign in to comment.