[DEV] add client interface accessible on pypi.org and basic tools to access on karanage (no token for now)

This commit is contained in:
Edouard DUPIN 2023-01-02 00:12:15 +01:00
parent 3c1eb707cb
commit 585630aeda
21 changed files with 545 additions and 58 deletions

View File

@ -22,7 +22,7 @@
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
</dependency>
</dependencies>

View File

@ -21,30 +21,61 @@ import java.util.List;
@Path("/state")
@Produces({MediaType.APPLICATION_JSON})
public class StateResource {
@GET
@Path("{group}/{topic:.*}")
//@RolesAllowed("USER")
@PermitAll
public static String getWithTopic(@PathParam("group") String groupName, @PathParam("topic") String topic) throws Exception {
Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
if (group == null) {
throw new Exception("Missing Group !!!");
}
DataInstant data = SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic, true);
return "{ \"time\": \"" + data.modify_date.toLocalDateTime().toString() + "\", \"data\":" + data.data + "}";
}
/*
public static DataInstant getWithTopic(@PathParam("group") String groupName, @PathParam("topic") String topic) throws Exception {
Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
if (group == null) {
throw new Exception("Missing Group !!!");
}
return SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic);
}
}*/
@GET
@Path("{group}")
//@RolesAllowed("USER")
@PermitAll
public String get(@PathParam("group") String groupName) throws Exception {
Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
if (group == null) {
throw new Exception("Missing Group !!!");
}
StringBuilder out = new StringBuilder("[");
List<DataInstant> datas = SqlWrapper.getsWhere(DataInstant.class, "group", "=", group.id, true);
boolean first = true;
for (DataInstant data : datas) {
if (first) {
first = false;
} else {
out.append(",");
}
out.append("{ \"time\": \"" + data.modify_date.toLocalDateTime().toString() + "\", \"topic\": \"" + data.topic + "\", \"data\":" + data.data + "}");
}
out.append("]");
return out.toString();
}
/*
public List<DataInstant> get(@PathParam("group") String groupName) throws Exception {
Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
if (group == null) {
throw new Exception("Missing Group !!!");
}
return SqlWrapper.getsWhere(DataInstant.class, "group", "=", group.id);
return SqlWrapper.getsWhere(DataInstant.class, "group", "=", group.id, true);
}
*/
@POST
@Path("{group}/{topic:.*}")

4
client/.karanage.json Normal file
View File

@ -0,0 +1,4 @@
{
"url": "http://localhost:20080/karanage/api/state",
"group": "home"
}

View File

@ -1,4 +1,9 @@
{
"config": {
"sleep": 0.1,
"display": false,
"topic": "PC/system"
},
"cpu": "auto",
"memory": "auto",
"swap": "auto",

View File

@ -0,0 +1,13 @@
Copyright karanage-interface Edouard DUPIN
Licensed under the Mozilla Public License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.mozilla.org/en-US/MPL/2.0/
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,3 @@
include README.md
include version.txt
include COPYING

View File

@ -0,0 +1,51 @@
KARANAGE-tools
==============
`karanage-tools` is thez generic tools to interact with the server REST
[Git interface...](https://gitea.atria-soft.org/kangaroo-and-rabbit/karanage)
git repository
--------------
https://gitea.atria-soft.org/kangaroo-and-rabbit/karanage
Installation
------------
Requirements: ``Python >= 3`` and ``pip``
Just run:
```
pip3 install karanage-tools
```
developpement for karanage-tools:
```
git clone https://gitea.atria-soft.org/kangaroo-and-rabbit/karanage
cd karanage/client/python/karanage-tools
./setup.py develop --user
```
Documentation
-------------
License (MPL v2.0)
---------------------
Licensed under the Mozilla Public License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.mozilla.org/en-US/MPL/2.0/
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -7,42 +7,11 @@ import subprocess
import json
from pathlib import Path
from typing import Dict, List
import requests
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", type=str, default=".karanage.json", help="json configuration file")
parser.add_argument("-u", "--url", type=str, default="http://localhost:20080/karanage/api/state", help="Base URL of the web service")
parser.add_argument("-g", "--group", type=str, default="home", help="Group the the message")
parser.add_argument("-t", "--topic", type=str, default="PC/system", help="Topic of the message")
parser.add_argument("-s", "--sleep", type=int, default=10, help="Periodicity of the messages")
args = parser.parse_args()
if Path(args.config).exists():
f = open(args.config, "r")
configuration = json.loads(f.read())
f.close()
else:
configuration = {
"cpu": "auto",
"memory": "auto",
"swap": "auto",
"drive": "auto",
"network": "auto",
}
def send_to_server(data: Dict) -> None:
ret = requests.post(f"{args.url}/{args.group}/{args.topic}", json=out)
if 200 <= ret.status_code <= 299:
pass # print(f" ==> done {ret}")
else:
print(f" ==> An error occured in sending message to the server !! {ret}")
import karanage
cpu_core_count = psutil.cpu_count(logical=False)
cpu_thread_count = psutil.cpu_count()
def get_mounts() -> Dict:
process = subprocess.Popen(
["mount", "-v"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
@ -71,7 +40,7 @@ mounting_points = get_mounts();
def filter(data: Dict, filter_list: List[str]) -> Dict:
out = {}
print(f"Request filter {data.keys()} with filter {filter_list}")
#print(f"Request filter {data.keys()} with filter {filter_list}")
for key in data:
if key in filter_list:
out[key] = data[key]
@ -148,30 +117,95 @@ def agglutinate(configuration, name, data):
return filter(data, configuration[name]["include"])
return none
while True:
out = {}
if need_process(configuration["cpu"]):
base_elem = create_cpu_data()
out["cpu"] = agglutinate(configuration, "cpu", base_elem)
if need_process(configuration["memory"]):
base_elem = create_memory_data()
out["memory"] = agglutinate(configuration, "memory", base_elem)
if __name__ == '__main__':
# Load arguments:
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", type=str, default="/etc/karanage/system.json", help="json configuration file")
parser.add_argument("-C", "--connection", type=str, default="/etc/karanage/connection.json", help="json configuration file")
if need_process(configuration["swap"]):
base_elem = create_swap_data()
out["swap"] = agglutinate(configuration, "swap", base_elem)
# This element are read from the connection file:
parser.add_argument("-u", "--url", type=str, default="http://localhost:20080/karanage/api/state", help="Base URL of the web service")
parser.add_argument("-g", "--group", type=str, default="home", help="Group the the message")
parser.add_argument("-T", "--token", type=str, default="", help="Token to access to the server")
if need_process(configuration["drive"]):
base_elem = create_drive_data()
out["drive"] = agglutinate(configuration, "drive", base_elem)
# This element are read from the configuration file:
parser.add_argument("-t", "--topic", type=str, default="PC/system", help="Topic of the message")
parser.add_argument("-s", "--sleep", type=int, default=30, help="Periodicity of the messages")
parser.add_argument("-d", "--display", help="Display the current state", action='store_true')
args = parser.parse_args()
if configuration["network"] == "auto" or "include" in configuration["network"]:
base_elem = create_network_data()
out["network"] = agglutinate(configuration, "network", base_elem)
if Path(args.config).exists():
f = open(args.config, "r")
configuration = json.loads(f.read())
f.close()
else:
configuration = {
"cpu": "auto",
"memory": "auto",
"swap": "auto",
"drive": "auto",
"network": "auto",
}
# manage the configuration model
if "config" not in configuration:
configuration["config"] = {}
if "display" not in configuration["config"]:
configuration["config"]["display"] = args.display
if "sleep" not in configuration["config"]:
configuration["config"]["sleep"] = args.sleep
if "topic" not in configuration["config"]:
configuration["config"]["topic"] = args.topic
#print("Read new value:")
print(json.dumps(out, indent=4))
send_to_server(out)
time.sleep(args.sleep)
if Path(args.connection).exists():
f = open(args.connection, "r")
connection = json.loads(f.read())
f.close()
else:
connection = {}
# manage the connection model
if "url" not in connection:
connection["url"] = args.url
if "group" not in connection:
connection["group"] = args.group
if "token" not in connection:
connection["token"] = args.token
# create the rest interface of karanage
restInterface = karanage.KaranageREST(
connection["url"],
connection["group"],
connection["token"])
while True:
out = {}
if need_process(configuration["cpu"]):
base_elem = create_cpu_data()
out["cpu"] = agglutinate(configuration, "cpu", base_elem)
if need_process(configuration["memory"]):
base_elem = create_memory_data()
out["memory"] = agglutinate(configuration, "memory", base_elem)
if need_process(configuration["swap"]):
base_elem = create_swap_data()
out["swap"] = agglutinate(configuration, "swap", base_elem)
if need_process(configuration["drive"]):
base_elem = create_drive_data()
out["drive"] = agglutinate(configuration, "drive", base_elem)
if configuration["network"] == "auto" or "include" in configuration["network"]:
base_elem = create_network_data()
out["network"] = agglutinate(configuration, "network", base_elem)
# display of needed:
if configuration["config"]["display"]:
print(json.dumps(out, indent=4))
# send message to the server:
try:
restInterface.send_to_server(configuration["config"]["topic"], out)
except karanage.KarangeSendError as ex:
print(f"Can not send to the server: {ex}")
time.sleep(configuration["config"]["sleep"])

View File

@ -0,0 +1,51 @@
#!/bin/python3
# Importing the library
import psutil
import argparse
import time
import subprocess
import json
from pathlib import Path
from typing import Dict, List
import karanage
if __name__ == '__main__':
# Load arguments:
parser = argparse.ArgumentParser()
parser.add_argument("-C", "--connection", type=str, default="/etc/karanage/connection.json", help="json configuration file")
parser.add_argument("-t", "--topic", type=str, default="", help="Topic of the message")
# This element are read from the connection file:
parser.add_argument("-u", "--url", type=str, default="http://localhost:20080/karanage/api/state", help="Base URL of the web service")
parser.add_argument("-g", "--group", type=str, default="home", help="Group the the message")
parser.add_argument("-T", "--token", type=str, default="", help="Token to access to the server")
args = parser.parse_args()
if Path(args.connection).exists():
f = open(args.connection, "r")
connection = json.loads(f.read())
f.close()
else:
connection = {}
# manage the connection model
if "url" not in connection:
connection["url"] = args.url
if "group" not in connection:
connection["group"] = args.group
if "token" not in connection:
connection["token"] = args.token
# create the rest interface of karanage
restInterface = karanage.KaranageREST(
connection["url"],
connection["group"],
connection["token"])
if args.topic == "":
data = restInterface.get_all()
print(f"Ret = {json.dumps(data, indent=4)}")
else:
data = restInterface.get_topic(args.topic)
print(f"Ret = {json.dumps(data, indent=4)}")

View File

View File

@ -0,0 +1,60 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
##
## @author Edouard DUPIN
##
## @copyright 2012, Edouard DUPIN, all right reserved
##
## @license APACHE v2.0 (see license file)
##
from setuptools import setup
import os
def readme():
with open('README.md') as f:
return f.read()
def read_version_file():
if not os.path.isfile("version.txt"):
return ""
file = open("version.txt", "r")
data_file = file.read()
file.close()
if len(data_file) > 4 and data_file[-4:] == "-dev":
data_file = data_file[:-4]
return data_file
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
setup(name='karanage-tools',
version=read_version_file(),
description='Karanage generic tools',
long_description=readme(),
url='https://gitea.atria-soft.org/kangaroo-and-rabbit/karanage',
author='Edouard DUPIN',
author_email='yui.heero@gmail.com',
license='MPL-2',
packages=['karanage-tools'],
classifiers=[
'Development Status :: 4 - Beta',
'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
'Programming Language :: Python',
'Operating System :: POSIX',
'Topic :: Software Development :: Libraries'
],
install_requires=[
'karanage'
],
long_description_content_type="text/markdown",
keywords='system cpu status',
scripts=[
'bin/karanage-system',
'bin/karanage-tools-get',
],
include_package_data = True,
zip_safe=False)
#To developp: sudo ./setup.py install
# sudo ./setup.py develop
#TO register all in pip: ./setup.py register sdist upload

View File

@ -0,0 +1 @@
0.1.0-dev

View File

@ -0,0 +1,13 @@
Copyright karanage-interface Edouard DUPIN
Licensed under the Mozilla Public License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.mozilla.org/en-US/MPL/2.0/
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,3 @@
include README.md
include version.txt
include COPYING

View File

@ -0,0 +1,51 @@
KARANAGE
========
`karanage` is a generic interface to communicate with the KARANAGE web service.
[Git interface...](https://gitea.atria-soft.org/kangaroo-and-rabbit/karanage)
git repository
--------------
https://gitea.atria-soft.org/kangaroo-and-rabbit/karanage
Installation
------------
Requirements: ``Python >= 3`` and ``pip``
Just run:
```
pip3 install karanage
```
developpement for KARANAGE:
```
git clone https://gitea.atria-soft.org/kangaroo-and-rabbit/karanage
cd karanage/client/python/karanage
./setup.py develop --user
```
Documentation
-------------
License (MPL v2.0)
---------------------
Licensed under the Mozilla Public License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.mozilla.org/en-US/MPL/2.0/
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
##
## @author Edouard DUPIN
##
## @copyright 2023, Edouard DUPIN, all right reserved
##
## @license MPL v2.0 (see license file)
##
from .interface import StateSystem, KaranageREST, KarangeSendError

View File

@ -0,0 +1,100 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
##
## @author Edouard DUPIN
##
## @copyright 2023, Edouard DUPIN, all right reserved
##
## @license MPL v2.0 (see license file)
##
import enum
import requests
import json
from typing import Dict, Optional
class KarangeSendError(Exception):
def __init__(self, message, error_id, error_message):
# Call the base class constructor with the parameters it needs
super().__init__(message)
# Now for your custom code...
self.error_id = error_id
self.error_message = error_message
def __str__(self):
return f"{Exception.__str__(self)} Status={self.error_id} message='{self.error_message}'"
class StateSystem(enum.Enum):
OK = "OK"
FAIL = "FAIL"
DOWN = "DOWN"
## Generic karanage sending system.
class KaranageREST:
def __init__(self, url: str, group: str, token: str) -> None:
"""
@brief Initialize the communication class.
@param[in] url URL of the karanage API server.
@param[in] group Group of the message (token need to have the autorisation to pubhied on it).
@param[in] token Token to validate the access on the application.
"""
self.url = url
self.group = group
self.token = token
self.root_url = f"{self.url}/{self.group}"
def send_to_server(self, topic: str, data: Optional[Dict], state: StateSystem = StateSystem.OK) -> None:
"""
@brief Send a message to the server.
@param[in] topic Topic where to publish the data.
@param[in] data: Data to send to the server
@param[in] state: State of the current system
"""
if data is None:
data = {}
param = {
"state": state,
}
header = {}
if self.token is not None and len(self.token) >15:
header['Authorization'] = f"zota {self.token}"
try:
ret = requests.post(f"{self.root_url}/{topic}", json=data, headers=header, params=param)
except requests.exceptions.ConnectionError as ex:
raise KarangeSendError(f"Fail connect server: {self.root_url}/{topic}", 0, str(ex))
if 200 <= ret.status_code <= 299:
pass
else:
raise KarangeSendError(f"Fail send message: {self.root_url}/{topic}", ret.status_code, ret.content.decode("utf-8"))
def get_all(self) -> Dict:
"""
@brief Get all the topic fom the server.
@return A dictionnary with the requested data.
"""
param = { }
header = { }
if self.token is not None and len(self.token) >15:
header['Authorization'] = f"zota {self.token}"
ret = requests.get(self.root_url, headers=header, params=param)
if 200 == ret.status_code:
return json.loads(ret.content.decode('utf-8'))
raise KarangeSendError(f"Fail get data: {self.root_url}", ret.status_code, ret.content.decode("utf-8"))
def get_topic(self, topic: str) -> Dict:
"""
@brief Get all the topic fom the server.
@return A dictionnary with the requested data.
"""
param = { }
header = { }
if self.token is not None and len(self.token) >15:
header['Authorization'] = f"zota {self.token}"
ret = requests.get(f"{self.root_url}/{topic}", headers=header, params=param)
#print(ret.content.decode('utf-8'))
if 200 == ret.status_code:
return json.loads(ret.content.decode('utf-8'))
raise KarangeSendError(f"Fail get data: {self.root_url}/{topic}", ret.status_code, ret.content.decode("utf-8"))

View File

56
client/python/karanage/setup.py Executable file
View File

@ -0,0 +1,56 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
##
## @author Edouard DUPIN
##
## @copyright 2023, Edouard DUPIN, all right reserved
##
## @license MPL v2.0 (see license file)
##
from setuptools import setup
import os
def readme():
with open('README.md') as f:
return f.read()
def read_version_file():
if not os.path.isfile("version.txt"):
return ""
file = open("version.txt", "r")
data_file = file.read()
file.close()
if len(data_file) > 4 and data_file[-4:] == "-dev":
data_file = data_file[:-4]
return data_file
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
setup(name='karanage',
version=read_version_file(),
description='Karanage interface is a simple interface to access to the karanage service to send and receive data',
long_description=readme(),
url='https://gitea.atria-soft.org/kangaroo-and-rabbit/karanage',
author='Edouard DUPIN',
author_email='yui.heero@gmail.com',
license='MPL-2',
packages=['karanage'],
classifiers=[
'Development Status :: 4 - Beta',
'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
'Programming Language :: Python',
'Operating System :: POSIX',
'Topic :: Software Development :: Libraries'
],
install_requires=[
'requests'
],
long_description_content_type="text/markdown",
keywords='kar karanage',
include_package_data = True,
zip_safe=False)
#To developp: sudo ./setup.py install --user
# sudo ./setup.py develop --user
#TO register all in pip: ./setup.py register sdist upload

View File

@ -0,0 +1 @@
0.1.0-dev