Skip to content

Commit 6ac6f59

Browse files
committed
Change polling to sched task, added future date, license year update
1 parent df597e3 commit 6ac6f59

18 files changed

+119
-72
lines changed

README.md

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# XL Release UCD Plugin
22

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

2120
## Requirements
2221

23-
* XL Release** 9.0.0+
22+
Changes introduced in version 2.0.0 -
23+
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.
24+
2. It is now possible to set a UCD Application Process Request for a future date/time deployment.
25+
26+
## Requirements
27+
28+
* XL Release** 9.8.0+
2429
* This plugin has been tested with XL Release 9.8.0 and UCD 7.1.0
2530

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

4045
### Application Process Request
4146

42-
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.
47+
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 .
48+
The Application Process Request ID is retrieved for display or stored in an XL Release variable.
4349

4450
![app_process_request](images/appProcessRequest.png)
4551

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

5258
### Synchronous Application Process
5359

54-
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.
60+
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.
5561

5662
![sync_process_request](images/synchronousAppProcess.png)
5763

@@ -67,30 +73,19 @@ Build and package the plugins with...
6773
./gradlew assemble
6874
```
6975

70-
### To run integration tests
71-
72-
1. Clone this git project to your local dev environment
73-
2. You will need to have Docker and Docker Compose installed.
74-
3. The XL-Release docker image uses the community trial license
75-
4. Open a terminal in the root of the xlr-ucd-plugin project and run the following gradle task
76-
77-
```bash
78-
./gradlew clean integrationTest
79-
```
80-
81-
The test will set up a temporary xlr/ucd testbed using docker. After testing is complete, the test docker containers are stopped and removed.
82-
8376
### To run demo or dev version (set up docker containers for both XLR and UCD platform)
8477

8578
NOTE:
8679

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

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

@@ -104,7 +99,13 @@ NOTE:
10499
docker-compose up
105100
```
106101

107-
* 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'.
102+
* After XLR and the UCD Platform starts up, open a terminal in the directory src/test/resources/docker/initialize and run
103+
104+
```bash
105+
./initialize_demo.sh
106+
```
107+
108+
* 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'.
108109

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

@@ -116,8 +117,7 @@ docker-compose down
116117

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

119-
[xlr-ucd-plugin-travis-image]: https://travis-ci.org/xebialabs-community/xlr-ucd-plugin.svg?branch=master
120-
[xlr-ucd-plugin-travis-url]: https://travis-ci.org/xebialabs-community/xlr-ucd-plugin
120+
121121
[xlr-ucd-plugin-codacy-image]: https://api.codacy.com/project/badge/Grade/da9c2f00342c40ad8efc7fbd1aaec063
122122
[xlr-ucd-plugin-codacy-url]: https://www.codacy.com/app/joris-dewinne/xlr-ucd-plugin
123123
[xlr-ucd-plugin-code-climate-image]: https://codeclimate.com/github/xebialabs-community/xlr-ucd-plugin/badges/gpa.svg

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins {
33
id 'nebula.release' version '13.0.0'
44
}
55

6-
version='1.5.0'
6+
version='2.0.0'
77

88
apply plugin: 'java'
99
apply plugin: 'idea'

images/appProcessRequest.png

-4.8 KB
Loading

images/status.png

-44 KB
Loading

images/synchronousAppProcess.png

13.4 KB
Loading

src/main/resources/synthetic.xml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version='1.0' encoding='UTF-8'?>
22
<!--
33
4-
Copyright 2020 XEBIALABS
4+
Copyright 2021 XEBIALABS
55
66
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:
77
@@ -51,18 +51,19 @@
5151
<property name="properties" category="input" label="Properties"
5252
description="Map containing the properties for the application process." kind="map_string_string"
5353
required="false"/>
54+
<property name="scheduleDate" category="input" label="(Optional) Future Date and Time to Schedule Process "
55+
description="You can optionally schedule the application process for a future start. Use a 24 hour clock for hours. Format: yyyy-mm-
56+
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"/>
5457
<!-- Outputs -->
5558
<property name="requestId" category="output" label="Request Id"
5659
description="The request id for further status retrieval" kind="string"/>
5760
</type>
5861

5962
<type type="ucd.SynchronousApplicationProcessRequest" extends="ucd.ApplicationProcessRequest">
60-
<!-- Input -->
61-
<property name="pollingInterval" category="input" default="10" required="true" kind="integer"
62-
description="Polling interval in seconds to check task status."/>
63-
<property name="numberOfPollingTrials" category="input" default="0" label="Polling Retry Count" required="true"
64-
kind="integer" description="Number of times to retry check for task status, 0 means indefinite."/>
65-
63+
<!-- Inputs -->
64+
<property name="scheduleDate" category="input" label="(Optional) Future Date and Time to Schedule Process "
65+
description="You can optionally schedule the application process for a future start. Use a 24 hour clock for hours. Format: yyyy-mm-
66+
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"/>
6667
<!-- Outputs -->
6768
<property name="requestStatus" category="output" label="Request Status" description="The request status"
6869
kind="string"/>
@@ -74,10 +75,6 @@
7475
<!-- Input -->
7576
<property name="requestId" category="input" label="Request Id"
7677
description="The request id for further status retrieval" kind="string"/>
77-
<property name="pollingInterval" category="input" default="10" required="true" kind="integer"
78-
description="Polling interval in seconds to check task status."/>
79-
<property name="numberOfPollingTrials" category="input" default="0" label="Polling Retry Count" required="true"
80-
kind="integer" description="Number of times to retry check for task status, 0 means indefinite."/>
8178

8279
<!-- Outputs -->
8380
<property name="requestStatus" category="output" label="Request Status" description="The request status"

src/main/resources/ucd/HttpRequest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2020 XEBIALABS
2+
# Copyright 2021 XEBIALABS
33
#
44
# 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:
55
#

src/main/resources/ucd/TestConnection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2020 XEBIALABS
2+
# Copyright 2021 XEBIALABS
33
#
44
# 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:
55
#

src/main/resources/ucd/UCDClient.py

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2020 XEBIALABS
2+
# Copyright 2021 XEBIALABS
33
#
44
# 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:
55
#
@@ -11,22 +11,31 @@
1111

1212
import json
1313
import time
14+
import logging
15+
import datetime
1416

1517
from ucd.HttpRequest import HttpRequest
1618

19+
logger = logging.getLogger(__name__)
20+
21+
logger.debug("In UCDClient")
22+
# In the case we have a future scheduled ucd_applicationprocessrequest, we don't want to log all those status messages
23+
shouldSupressLogging = False
24+
1725

1826
def check_response(response, message):
1927
if not response.isSuccessful():
2028
raise Exception(message)
2129

2230

2331
class UCD_Client(object):
24-
def __init__(self, http_connection, username=None, password=None, verify=True):
32+
def __init__(self, http_connection, task, username=None, password=None, verify=True):
2533
self.http_request = HttpRequest(http_connection, username, password, verify)
34+
self.task = task
2635

2736
@staticmethod
28-
def create_client(http_connection, username=None, password=None, verify=True):
29-
return UCD_Client(http_connection, username, password, verify)
37+
def create_client(http_connection, task, username=None, password=None, verify=True):
38+
return UCD_Client(http_connection, task, username, password, verify)
3039

3140
def ucd_listsystemconfiguration(self, variables):
3241
system_configuration_endpoint = "/cli/systemConfiguration"
@@ -39,7 +48,6 @@ def ucd_listsystemconfiguration(self, variables):
3948
variables['systemConfiguration'] = result
4049
return result
4150

42-
# TODO: add 'date' option for scheduled deployments
4351

4452
def ucd_applicationprocessrequest(self, variables):
4553
application_process_request_endpoint = "/cli/applicationProcessRequest/request"
@@ -49,13 +57,22 @@ def ucd_applicationprocessrequest(self, variables):
4957
body = {'application': variables['application'], 'applicationProcess': variables['applicationProcess'],
5058
'environment': variables['environment'], 'properties': variables['properties'],
5159
'versions': versions_list}
60+
if variables['scheduleDate'] is not None and len(variables['scheduleDate']) > 0:
61+
if self.vaild_dateTime(variables['scheduleDate']):
62+
logger.debug("dateTimeString is valid")
63+
body.update({"date": variables['scheduleDate']})
64+
else:
65+
logger.debug("dateTimeString is Not valid")
66+
raise Exception("Future schedule date is configured but is not in proper format. See field description.")
67+
5268
print "Sending request: [%s]\n" % json.dumps(body)
5369
application_process_request_response = self.http_request.put(application_process_request_endpoint,
5470
json.dumps(body), contentType='application/json')
5571
check_response(application_process_request_response,
5672
"Failed to execute application process request. Server return [%s], with content [%s]" % (
5773
application_process_request_response.status,
5874
application_process_request_response.response))
75+
logger.debug("\napplicationprocessrequest respone was %s\n" % json.loads(application_process_request_response.getResponse()))
5976
result = json.loads(application_process_request_response.getResponse())["requestId"]
6077
variables['requestId'] = result
6178
return result
@@ -71,6 +88,9 @@ def application_process_request_status(self, request_id):
7188
return json.loads(application_process_request_status_response.getResponse())
7289

7390
def ucd_applicationprocessrequeststatus(self, variables):
91+
#logger.debug("In ucd_applicationprocessrequeststatus")
92+
global shouldSupressLogging
93+
7494
'''
7595
The UCD request returns the following statuses:
7696
CANCELING
@@ -101,12 +121,22 @@ def ucd_applicationprocessrequeststatus(self, variables):
101121
variables['requestStatus'] = request_response["status"]
102122
variables['requestResult'] = request_response["result"]
103123

104-
# update task status
105-
print ("Received Request Status: [%s] with Request Result: [%s]\n").format(variables['requestStatus'], variables['requestResult'])
124+
# log task status
125+
if variables['requestResult'] is not None and variables['requestResult'] in ('SCHEDULED FOR FUTURE'):
126+
if not shouldSupressLogging:
127+
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']))
128+
#print ("Received Request Status: [%s] with Request Result: [%s], will surpress printout until result change.\n" % (variables['requestStatus'], variables['requestResult']))
129+
shouldSupressLogging = True
130+
else:
131+
logger.debug("Received Request Status: Request Id: [%s], Request Status: [%s] with Request Result: [%s].\n" % (variables['requestId'], variables['requestStatus'], variables['requestResult']))
132+
#print ("Received Request Status: [%s] with Request Result: [%s].\n" % (variables['requestStatus'], variables['requestResult']))
133+
# set to false so the print output from application_process_request_status will print at least once
134+
shouldSupressLogging = False
135+
106136

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

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

121151
def ucd_synchronousapplicationprocessrequest(self, variables):
122152
self.ucd_applicationprocessrequest(variables)
123-
task.schedule('ucd/UCDTask.wait-for-status.py')
153+
self.task.schedule('ucd/UCDTask.wait-for-status.py')
154+
155+
def vaild_dateTime(self, dateTimeString):
156+
logger.debug("In valid_dateTime, dateTimeString = %s" % dateTimeString)
157+
try:
158+
datetime.datetime.strptime(dateTimeString, '%Y-%m-%d %H:%M')
159+
return True
160+
except ValueError:
161+
return False
124162

src/main/resources/ucd/UCDClientUtil.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2020 XEBIALABS
2+
# Copyright 2021 XEBIALABS
33
#
44
# 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:
55
#
@@ -14,6 +14,6 @@
1414
class UCD_Client_Util(object):
1515

1616
@staticmethod
17-
def create_ucd_client(container, username, password, verifySsl):
18-
client = UCD_Client.create_client(container, username, password, verifySsl)
17+
def create_ucd_client(container, task, username, password, verifySsl):
18+
client = UCD_Client.create_client(container, task, username, password, verifySsl)
1919
return client

0 commit comments

Comments
 (0)