Skip to content
This repository has been archived by the owner on Dec 6, 2023. It is now read-only.

Connectors Installer #105

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cc374a2
WIP: Implemented Form Validation
valerio-pizzichini Nov 30, 2020
a467e89
Adapted POST data for backend action
valerio-pizzichini Nov 30, 2020
3d6c214
Fixed button not resetting form properly
valerio-pizzichini Nov 30, 2020
991db64
Added UI Validation on Form's Input fields
valerio-pizzichini Nov 30, 2020
3a3658b
Implemented github service
valerio-pizzichini Dec 1, 2020
368490e
Cleaned logs
valerio-pizzichini Dec 1, 2020
a259702
Implementing UI IO connectors
valerio-pizzichini Dec 3, 2020
fbeb370
Implemented first test of connection action creation
valerio-pizzichini Dec 4, 2020
e96be0e
Implemented action that creates actions according to a list of connec…
valerio-pizzichini Dec 6, 2020
a71031b
Fixed UI Form validation
valerio-pizzichini Dec 4, 2020
09aa6f1
Added list of responses as return
valerio-pizzichini Dec 6, 2020
bf1881f
Implemented a generic action that create connector's ction
valerio-pizzichini Dec 7, 2020
16acb9c
Implemented custom connectors retrieve and adaptive menu
valerio-pizzichini Dec 7, 2020
ff66c76
Implemented the custom connectors store; Added custom imports to the …
valerio-pizzichini Dec 7, 2020
65778eb
WIP: Implemented Form Validation
valerio-pizzichini Nov 30, 2020
a6b9fd1
Adapted POST data for backend action
valerio-pizzichini Nov 30, 2020
ca26670
Fixed button not resetting form properly
valerio-pizzichini Nov 30, 2020
4d294a2
Cleaned code
valerio-pizzichini Dec 8, 2020
52af7c8
Cleaned code
valerio-pizzichini Dec 8, 2020
d8bcd90
Improved custom connectors flow
valerio-pizzichini Dec 13, 2020
a1659eb
Fixed select_connector action; fixed amount display when undefined;
valerio-pizzichini Dec 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions admin/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ packages:
function: packages/util/upload.py
docker: pagopa/action-python-v3.7:2020-11-16
web: raw
select_connectors:
function: packages/util/select_connectors.py
docker: sciabarracom/actionloop-python-v3.7:2020-10-21
web: true
get_custom_connectors:
function: packages/util/get_custom_connectors.py
docker: sciabarracom/actionloop-python-v3.7:2020-10-21
web: true
import:
function: packages/util/import.js
#docker: sciabarracom/action-nodejs-v10:2020-10-21
Expand Down
15 changes: 15 additions & 0 deletions admin/packages/util/get_custom_connectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from nimbella import redis
import json


def main(args):

red = redis()

connectors = red.get('connectors')

connectors = connectors.decode("utf-8").split(",") if connectors else []

return {"body": {"details": {
"connectors": connectors
}}}
178 changes: 178 additions & 0 deletions admin/packages/util/select_connectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
from requests import get, put
from base64 import b64encode
from os import environ
from json import loads, dumps
from nimbella import redis


def main(args):

connectors = args.get('connectors')

if not connectors:
return {"body": {"detail": "connectors list is empty"}}

github_service = GithubService()
connectors_response = github_service.get_connectors()
valid_connectors = [connector for connector in connectors_response
if connector['name'] in connectors
]

if not valid_connectors:
return {"body": {"detail": "no valid connectors names provided"}}

ow_service = OWService()
red = redis()

responses = []
created_connectors = []
for connector in valid_connectors:

binary_connector = github_service.get_connector_file(
connector['file_path']
)

create_response = ow_service.create_action(
connector,
binary_connector
)

responses.append(create_response)

if 'error' not in create_response:
created_connectors.append(connector['name'])

red.set('connectors', ",".join(created_connectors))
return {"body": {"detail": responses}}


class RequestError(Exception):

def __init__(self, message="Error during request"):
super().__init__(message)


class GithubService():
"""
Class responsible to communicate with the Github Api

Raises:
RequestError: Error during request against Github Api Server
RequestError: Error during request against Github Api Server
"""
GITHUB_REPO_HOST = 'https://sf3ris.github.io'
GITHUB_REPO_NAME = '/io-gateway-connectors/'
GITHUB_REPO_INDEX = 'index.json'

def __init__(self):
pass

def get_connectors(self):
"""
Retrieves a list of the current available connectors

Raises:
RequestError: Error during request against Github Api Server

Returns:
list: List of available connectors
"""
url = self.GITHUB_REPO_HOST \
+ self.GITHUB_REPO_NAME \
+ self.GITHUB_REPO_INDEX

response = get(url)

if response.status_code != 200:
raise RequestError

connectors = response.json()
return connectors

def get_connector_file(self, connector_name):
"""
Retrive the connector binary data

Args:
connector_name (string): Connector's name

Raises:
RequestError: Error during request against Github Api Server

Returns:
bytes: Connector's binary data
"""
url = self.GITHUB_REPO_HOST + self.GITHUB_REPO_NAME + connector_name
response = get(url)

if response.status_code != 200:
raise RequestError("Error downloading binary connector file")

return response.content


class OWService():
"""
Class responsible to communicate with the OpenWhisk REST API
"""
def __init__(self):
self.__host = environ["__OW_API_HOST"]
self.__api_key = environ["__OW_API_KEY"].split(":")
self.__namespace = "guest"

def create_action(self, connector, binary_data):
"""
Creates a new connection

Args:
action_name (string): Action's name to be create
binary_data (bytes): Connector's binary data
"""
action_name = "util/{}".format(connector['name'])
url = "{}/api/v1/namespaces/{}/actions/{}?overwrite=true&web=true".format(
self.__host,
self.__namespace,
action_name
)

data = {
"namespace": self.__namespace,
"name": "123",
"exec": {
"kind": connector['config']['kind'],
"binary": "true",
"code": b64encode(binary_data).decode("utf-8", "ignore"),
"main": connector['config']['main'],
"image": connector['config']['image'],
},
"annotations": [
{
"key": "web-export",
"value": True
}
]
}
headers = {'Content-type': 'application/json'}

try:

response = put(
url,
json=data,
auth=(self.__api_key[0], self.__api_key[1]),
headers=headers
)
if('error' in response.text):
raise Exception(response.text)

return "{} connector's action created successfully.".format(
action_name
)

except Exception as e:
return {
"message": "Error creating action for connector {}".format(
action_name
),
"error": str(e)
}
5 changes: 5 additions & 0 deletions admin/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ packages:
web: true
- name: upload
web: raw
- name: select_connectors
web: true
- name: get_custom_connectors
web: true
runtime: sciabarracom/actionloop-python-v3.7:2020-10-21
- name: import
web: true
- name: sample
Expand Down
7 changes: 5 additions & 2 deletions admin/web/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import Send from "./Send.svelte";
import Ship from "./Ship.svelte";
import Import from "./Import.svelte";
import Connectors from "./Connectors.svelte";

let menu = ""
let key = ""
Expand All @@ -23,7 +24,7 @@ onMount(() => {
navigate(menu, key)
})

onDestroy(url.subscribe((href) => {
onDestroy(url.subscribe((href) => {
[menu, key, api] = parseURL(href)
console.log("menu=",menu, "key=", key, "api=", api)
}))
Expand All @@ -50,9 +51,11 @@ onDestroy(url.subscribe((href) => {
{:else if menu=="import"}
<Import {api} action="/util/import"/>
{:else if menu=="custom"}
<Import {api} action="/iosdk/import"/>
<Import {api} action={key ? `/util/${key}` : "/iosdk/import"} />
{:else if menu=="devel"}
<Devel {api} {key}/>
{:else if menu=="connectors"}
<Connectors {api} {key} />
{/if}
</div>
</div>
Expand Down
128 changes: 128 additions & 0 deletions admin/web/src/Connectors.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<script>

import { onMount } from 'svelte';
import { githubService } from './services/github.service.js';
import { ioSDKService } from './services/iosdk.service';
import { customConnectors } from "./store"

let loading = false;
let connectors = [];
let connectorsStateValue = []

const unsubscribe = customConnectors.subscribe(customConnectors => {
connectorsStateValue = customConnectors;
});

const init = async () => {

await getConnectorsList(
await getCustomConnectors()
);

}

const getConnectorsList = async ( custom_connectors = []) => {

try{

const response = await githubService.getIoGetawayConnectors();

connectors = response.map( e => ({...e, checked: connectorsStateValue.includes(e.name)}));


} catch(e) {

console.log(e);

}

}

const getCustomConnectors = async () => {

try{

const response = await ioSDKService.getCustomConnectors();

customConnectors.update( connectors => response?.details?.connectors || [] );

} catch(e) {

console.log(e);

}

}

onMount( async () => {
await init()
})

const handleCheckBox = ( connectorName, event ) => {

const connectorIndex = connectors.findIndex( connector => connector.name === connectorName );

if(connectorIndex !== -1) {

connectors[connectorIndex].checked = event.target.checked;

}

}

const onSubmit = async () => {

loading = true;
try{

const response = await ioSDKService.createConnectors(
connectors.filter( connector => connector.checked).map( connector => connector.name)
);

} catch( e ) {

console.error( e )

}

init();

loading = false

}

</script>

<div>

<h1> Connectors </h1>
<form>
{#each connectors as connector}

<div class="form-check">

<input
checked={connectors.find( c => c.name === connector.name && c.checked )}
on:change={ e => handleCheckBox( connector.name, e )}
class="form-check-input"
id={"checkbox_"+connector.name}
type="checkbox"/>
<label
class="form-check-label"
for={"checkbox_"+connector.name}>
{connector.name}
</label>

</div>

{/each}
<button
disabled={loading}
type="button"
class="btn btn-primary"
on:click={onSubmit}>
Submit
</button>
</form>

</div>
Loading