vRO8 Import Workflow

Share on:

How to import legacy workflow files into vRO8

Introduction

vRealize Orchestrator version 8 does not provide a way to export or import individual workflows via the GUI. If you have some legacy workflows on your hard disk and would like to import them into your shiny new vRO8 instance, you need to create a package on a legacy vRO7 system, export it and import the package into vRO8. Let's see if we can do it easier.

API definition

The vRealize Orchestrator API provides a REST API to interact with vRO. The Content Service allows us to import a workflow. According to the specification the workflow is sent to /content/workflows/{categoryId} as a Multipart Content-type. RFC 2387 describes the details of this Content-type.

We need to know the Id of the folder (WorkflowCategory). The following Javascript code will print it:

1var folder = Server.getWorkflowCategoryWithPath("test/import");
2System.log(System.getObjectId(folder));

There it is:

12021-10-31 21:02:06.118 +01:00 INFO __item_stack:/item1
22021-10-31 21:02:06.122 +01:00 INFO 8a7480e57c8e421d017cd78e673619f1
32021-10-31 21:02:06.126 +01:00 INFO __item_stack:/item0

Import using CLI

The Spring sample in the API documentation gives some hints how to format the Multipart data to post: the part representing the workflow should be called "file".

Using curl we can upload a workflow to vRO with the following command, knowing the Workflow Category Id (target folder). In case a workflow with the same workflow Id exists, we overwrite it. The name of the object within the multipart data is specified by file=. The actual file content is loaded by using the @ symbol.

1curl -k -u 'cfgadmin:VMware123!' -H 'Content-Type: multipart/form-data' \
2"https://vra8.corp.local/vco/api/content/workflows/8a7480e57c8e421d017cd78e673619f1?overwrite=true" \
3-F 'file=@HelloWorld.workflow'

The result:

Multipart Content-type

Let's check what data did curl send to upload the file:

1curl -k -u 'cfgadmin:VMware123!' -H 'Content-Type: multipart/form-data' \
2"https://vra8.corp.local/vco/api/content/workflows/8a7480e57c8e421d017cd78e673619f1?overwrite=true" \
3-F 'file=@HelloWorld.workflow' --trace-ascii -

Highlighted are: the Content-type, boundary value and the Content-Disposition Headers:

 1...
 20000: POST /vco/api/content/workflows/8a7480e57c8e421d017cd78e673619f1
 30040: ?overwrite=true HTTP/2
 40058: Host: vra8.corp.local
 50070: authorization: Basic Y2ZnYWRtaW46Vk13YXJlMTIzIQ==
 600a3: user-agent: curl/7.68.0
 700bc: accept: */*
 800c9: content-length: 1202
 900df: content-type: multipart/form-data; boundary=--------------------
10011f: ----4a56c5c66e96749e
110135:
12<= Recv SSL data, 5 bytes (0x5)
130000: ....9
14== Info: Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
15=> Send SSL data, 5 bytes (0x5)
160000: ....!
17=> Send SSL data, 5 bytes (0x5)
180000: .....
19=> Send data, 1202 bytes (0x4b2)
200000: --------------------------4a56c5c66e96749e
21002c: Content-Disposition: form-data; name="file"; filename="HelloWorl
22006c: d.workflow"
230079: Content-Type: application/octet-stream
2400a1:
2500a3: PK........V._S................workflow-info.....0......!......pS
2600e3: .....%=iQrrI<|{...C.n-.k.n.\.C........>....J.i..p..t.....s.%3.K.
270123: \|Z.Z..,LU.#....D.......l.)....PK......t...z...PK........V._S...
280163: .............workflow-content.U.n.@.=.~...H..8..J..Tu....$...Nj.
2901a3: .+N....s.'.c;UJ.h..}...3..p..< E.....@..s....t.....f.1.!.3LU{.k
3001e3: ...{.O0...V.Y..&D...2.3...-....p9..[!.G.H...TVn....6.Zrm..t8.>..
310223: 1...J<V..+.q.+F.e...m.*'F.uF&....,-/.7.{Y..Kj.^...KMb..OO.=.*...
320263: ..f...".9.D*....?.....]=....*+.31=.'fL....G..w\.....G."+.:_y..~.
3302a3: U.<B..3..P.P.ie...tL..{.k.u....3}.../..T.G....Nk;...|..K(..<.Q.n
3402e3: q.....EB..J.F....>.3NyVN.>.<.^.;...;...O .ce..u..:-.IF.J...*o#+.
350323: ..%j}...?.V..q.....0!.......~=]G..8......T..%.....6.NY...a}z.v..
360363: f...9c.;...]....R...9TD.;M.m.|..{dN..^.."..f..z..FG3...mK~.!.j..
3703a3: C.^.C%.j....]l....I....i.T}.{...K../...eO.......N.O...g..K{..a..
3803e3: PK....++c.......PK..........V._S....t...z.....................wo
390423: rkflow-infoPK..........V._S..++c.........................workflo
400463: w-contentPK..........y...P.....
410484: --------------------------4a56c5c66e96749e--
42...

The actual file data is a ZIP file.

Import using vRO

The inputs

To automate the workflow import with vRO, we need to load a the file and send its content via vRO REST API, using the Multipart Content-type format examined above.

The MimeAttachment type allows us to upload files to vRO. We also want to select the folder to import the workflow into, we can use the WorkflowCategory type for that input:

On the Input Form designer let's change the display type of the WorkflowCategory type to Tree Picker to get a nice tree browser.

This will result in the following form:

MimeAttachment issues

The Cumulative Update for vRealize Orchestrator 7.5 ResolvedList describes a problem with binary data represented by MimeAttachment:

Previously instances of MimeAttachment provided only a property "content" which returns/accepts a string. This causes issues with non-textual data as the bytes are interpreted as String and the content is malformed. A new JavaScript type is exposed to the scripting api - ByteBuffer. It can be initialised from a base64 string or from an existing ByteBuffer. Instances of MimeAttachment now have a new get/set propety "buffer" which returns/accepts a ByteBuffer.

Unfortunately I could not find any examples on how to use this new buffer property of ByteBuffer type (and the content property gives an HTTP 500 error on the API). If you know how to use it, please leave a comment at the bottom!

Sending the file to vRO REST API using Python

vRO8 with vRA/vRealize Suite Advanced/vCloud Suite Advanced or Enterprise license is capable of running Python, NodeJS and PowerShell scripts as well. Let's try Python!

If we print the MimeAttachment object in Python, we'll see the following output:

12021-10-31 23:54:57.647 +01:00 INFO [HelloWorld.workflow,application/octet-stream,991]
22021-10-31 23:54:57.648 +01:00 INFO UEsDBBQACAgIAFaxX1MAAAAAAAAAAAAAAAANAAAAd29ya2Z...

The first line contains the filename and Content-type, the second line contains the base64 encoded file content. We'll use this information to extract the information from the object.

I reused Doug Hellmann's implementation of Multipart Content type available at Python 3 Module of the Week:

 1import io
 2import mimetypes
 3from urllib import request
 4import uuid
 5import ssl
 6import base64
 7
 8def handler(context, inputs):
 9
10    # Create the form with simple fields
11    form = MultiPartForm()
12
13    # Add the file
14    form.add_file(
15        'file', inputs["file"].split(',', 1)[0][1:],       # 'HelloWorld.workflow',
16        fileHandle=io.BytesIO(base64.b64decode(inputs["file"].split('\n',1)[1])))
17    # Build the request, including the byte-string
18    # for the data to be posted.
19    data = bytes(form)
20    r = request.Request(context["vcoUrl"] + "/api/content/workflows/" + inputs["categoryId"] + "?overwrite=true", data=data)
21    r.add_header('Content-type', form.get_content_type())
22    r.add_header('Authorization', 'Bearer ' + context["getToken"]())
23
24    print('SERVER RESPONSE:')
25    # disable SSL verification
26    print(request.urlopen(r, context=ssl.SSLContext()).read().decode('utf-8'))
27
28    class MultiPartForm:
29    ...

context["vcoUrl"] provides the internal vRO REST API URL http://localhost:8280/vco, and the getToken() function will acquire a valid token against the API.

Wrap-up

MimeAttachment is a useful vRO type, when we need to process a file. Python can be used to communicate back to vRO using the loopback URL (context["vcoUrl"]) and a token provided by the getToken() function.

You can download the com.test.python package containing the workflow from GitHub: https://github.com/kuklis/vro8-packages