Salut Fabien, Nous n'allons pas traduire la documentation. Mais tu vas voir de plus en plus d'article anglais traduit en français.
- Se connecter pour publier des commentaires
Salut Fabien, Nous n'allons pas traduire la documentation. Mais tu vas voir de plus en plus d'article anglais traduit en français.
Bonjour,
Je vous envoie mes coordonnées par messages privées, nous pourrons discuter de votre besoin sur un autre canal (mail par exemple).
Cordialement,
Guillaume
Article important, à partir de docker desktop 4.7.0
Cette erreur ce produit.
C'est un plaisir de partager ce moment avec vous !
Super article, j'adore, il parle aussi bien à des personnes techniques que de culture générale sur les bases de données (SQL, NoSQL, stockage colonne, stockage en ligne).
Bref, un must read !
Peux tu nous aider sur cette question ?
Bonjour Alexandre,
Tu trouveras sur ce git, la meme version que celle de lucas mais avec un docker-compose et un dockerfile mis à jour pour installer automatiquement la partie front.
https://github.com/grongierisc/fhir-form
Je n'ai pas eu de problème de dépendance avec node 14. Ton erreur vient peut etre du fait que tu es en node 16.
Les versions client d'IRIS/ HealthShare sont fournis avec l'installation du Serveur dans le dossier suivant :
<dossier d'install>/devexample sous linux :
/usr/irissys/dev/dotnet/
`-- bin
|-- InterSystems.Data.Bindings.2.0.0.nupkg
|-- InterSystems.Data.IRISClient.2.0.0.nupkg
|-- InterSystems.Data.Utils.2.0.0.nupkg
|-- InterSystems.Data.XEP.2.0.0.nupkg
|-- net5.0
| |-- InterSystems.Data.Gateway.pdb
| |-- InterSystems.Data.Gateway.xml
| |-- InterSystems.Data.GatewayArm
| |-- InterSystems.Data.GatewayLinux
| |-- InterSystems.Data.GatewayOSX
| |-- InterSystems.Data.IRISClient.dll
| |-- InterSystems.Data.IRISClient.xml
| |-- InterSystems.Data.Utils.dll
| |-- InterSystems.Data.Utils.xml
| `-- Newtonsoft.Json.dll
`-- net6.0
|-- InterSystems.Data.Gateway.pdb
|-- InterSystems.Data.Gateway.xml
|-- InterSystems.Data.GatewayArm
|-- InterSystems.Data.GatewayLinux
|-- InterSystems.Data.GatewayOSX
|-- InterSystems.Data.IRISClient.dll
|-- InterSystems.Data.IRISClient.xml
|-- InterSystems.Data.Utils.dll
|-- InterSystems.Data.Utils.xml
`-- Newtonsoft.Json.dllToutes ces libraires peuvent etre utilisées sur une autre machine, elles ouvreront une socket TCP pour effectuer la connection sur le superserver port (1972 par default, 51773 pour HealthShare, enfin je crois).
Bonjour,
%Net.HttpRequest n'est pas une classe de type message (Ens.Request).
Il faut encapsuler le JSON en provenance du Service dans une classe qui herite de Ens.Request.
Bonjour,
Je ne peux pas reproduire votre erreur. Il me manque quelques informations.
Ce que j'ai fait jusqu'à présent est :
from dataclasses import dataclass
import pandas as pd
from grongier.pex import BusinessOperation,Message
from sqlalchemy import create_engine, types
@dataclass
class DFrameRequest(Message):
dframe: pd.DataFrame
class FileOperationEmbedded(BusinessOperation):
tablename = None
engine = None
def on_init(self):
if not hasattr(self, "dsnIris"):
self.dnsIris = 'iris+emb:///'
if not hasattr(self, "schema"):
self.schema = 'Toto'
self.engine = create_engine(self.dnsIris)
return None
def on_message(self, request:DFrameRequest):
df = pd.DataFrame(request.dframe.col)
for row in request.dframe.col:
df = pd.DataFrame.from_dict(row, orient='index').T.reset_index(drop=True)
try:
df.to_sql(name=self.tablename, con=self.engine, if_exists='append', index=False, schema=self.schema,
dtype={'id': types.INTEGER, 'col_type': types.VARCHAR(50), 'col_center': types.VARCHAR(50),
'col_name': types.VARCHAR(50), 'col_issue_name': types.VARCHAR(50),
'col_model': types.VARCHAR(50), 'col_treatment': types.VARCHAR(50),
'source': types.VARCHAR(50), 'filename': types.VARCHAR(100), 'created_at': types.TIMESTAMP})
except Exception as e:
self.log_info(f"Une erreur s'est produite : {e}")
return None
if __name__ == '__main__':
# create a new instance of the business operation
bo = FileOperationEmbedded()
# initialize the business operation
bo.on_init()
# create a new message
msg = DFrameRequest(pd.DataFrame())
msg.dframe.col = [
{'id': 1, 'col_type': 'type1', 'col_center': 'center1', 'col_name': 'name1', 'col_issue_name': 'issue1',
'col_model': 'model1', 'col_treatment': 'treatment1', 'source': 'source1', 'filename': 'file1',
'created_at': '2021-10-01 00:00:00'},
{'id': 2, 'col_type': 'type2', 'col_center': 'center2', 'col_name': 'name2', 'col_issue_name': 'issue2',
'col_model': 'model2', 'col_treatment': 'treatment2', 'source': 'source2', 'filename': 'file2',
'created_at': '2021-10-02 00:00:00'}
]
# send the message to the business operation
bo.on_message(msg)
print("Done")
Ensuite, à partir de votre code, je peux voir les problèmes suivants :
self.tablename n'est pas initialiséeFileOperationEmbedded n'est peut-être pas le meilleur nom pour votre classe car ce n'est pas une opération de fichierJ'ai modifié votre code pour corriger ces problèmes :
from dataclasses import dataclass
import pandas as pd
from grongier.pex import BusinessOperation,Message
from sqlalchemy import create_engine, types
@dataclass
class DFrameRequest(Message):
dframe: pd.DataFrame
class IrisSqlAlchmyEmbedded(BusinessOperation):
tablename = None
engine = None
def on_init(self):
if not hasattr(self, "dsnIris"):
self.dnsIris = 'iris+emb:///'
if not hasattr(self, "schema"):
self.schema = 'Toto'
if not hasattr(self, "tablename") or self.tablename is None:
self.tablename = 'mytable'
self.engine = create_engine(self.dnsIris)
return None
def on_message(self, request:DFrameRequest):
try:
request.dframe.to_sql(name=self.tablename, con=self.engine, if_exists='append', index=False, schema=self.schema,
dtype={'id': types.INTEGER, 'col_type': types.VARCHAR(50), 'col_center': types.VARCHAR(50),
'col_name': types.VARCHAR(50), 'col_issue_name': types.VARCHAR(50),
'col_model': types.VARCHAR(50), 'col_treatment': types.VARCHAR(50),
'source': types.VARCHAR(50), 'filename': types.VARCHAR(100), 'created_at': types.TIMESTAMP})
except Exception as e:
print(f"Une erreur s'est produite : {e}")
return None
if __name__ == '__main__':
# create a new instance of the business operation
bo = IrisSqlAlchmyEmbedded()
# initialize the business operation
bo.on_init()
# create a new message
msg = DFrameRequest(pd.DataFrame([
{'id': 1, 'col_type': 'type1', 'col_center': 'center1', 'col_name': 'name1', 'col_issue_name': 'issue1',
'col_model': 'model1', 'col_treatment': 'treatment1', 'source': 'source1', 'filename': 'file1',
'created_at': '2021-10-01 00:00:00'},
{'id': 2, 'col_type': 'type2', 'col_center': 'center2', 'col_name': 'name2', 'col_issue_name': 'issue2',
'col_model': 'model2', 'col_treatment': 'treatment2', 'source': 'source2', 'filename': 'file2',
'created_at': '2021-10-02 00:00:00'}
]))
# send the message to the business operation
bo.on_message(msg)
print("Done")
Bonjour @Cyril Grosjean,
Je ne suis pas sur de comprendre le problème, il me manque peut-etre informations.
De ce que j'ai compris :
Class TEST.maclasse Extends %RegisteredObject
{
ClassMethod testPython() As %Status [ Language = python ]
{
print("Ok")
}
}
Le problème :
TEST>do ##class(TEST.maclasse).testPython()
Ok
SUPPLY_CHAIN>do ##class(TEST.maclasse).testPython()
<OBJECT DISPATCH> *python object not found
Est-ce que j'ai bien compris ?
Si oui :
Si non :
est-il possible d'avoir un extrait de votre dockefile + des scripts de compilation ?
une possible solution peut etre de s'assurer que la compliation est lieu dans le même layer docker :
ARG IMAGE=intersystemsdc/irishealth-community:latest
FROM $IMAGE
USER root
# Update package and install sudoRUN apt-get update && apt-get install -y \
nano \
python3-pip \
python3-venv \
sudo && \
/bin/echo -e ${ISC_PACKAGE_MGRUSER}\\tALL=\(ALL\)\\tNOPASSWD: ALL >> /etc/sudoers && \
sudo -u ${ISC_PACKAGE_MGRUSER} sudo echo enabled passwordless sudo-ing for${ISC_PACKAGE_MGRUSER}# create dev directoryWORKDIR /opt/irisapp
RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp
USER ${ISC_PACKAGE_MGRUSER}
# Copy source files to imageCOPY . /opt/irisapp
# load demo stuffRUN iris start IRIS \
&& iris session IRIS < /opt/irisapp/iris.script.test \
&& iris session IRIS < /opt/irisapp/iris.script.supply \
&& iris stop IRIS quietly
iris.script.test :
zn"TEST"// Load ObjectScript source fileszw$SYSTEM.OBJ.ImportDir("/opt/irisapp/src/test", "*.cls", "cubk", .tErrors, 1)
// exit scripthiris.script.supply :
zn"SUPPLY_CHAIN"// Load ObjectScript source fileszw$SYSTEM.OBJ.ImportDir("/opt/irisapp/src/supply", "*.cls", "cubk", .tErrors, 1)dans l'example ci-dessus dans le dockerfile, les derniers lignes sont exécutées sur le meme layer docker avec deux scripts differents pour des questions de maintenabilité.
Il est déconseillé de faire comme ci-dessous :
ARG IMAGE=intersystemsdc/irishealth-community:latest
USER root
# Update package and install sudoRUN apt-get update && apt-get install -y \
nano \
python3-pip \
python3-venv \
sudo && \
/bin/echo -e ${ISC_PACKAGE_MGRUSER}\\tALL=\(ALL\)\\tNOPASSWD: ALL >> /etc/sudoers && \
sudo -u ${ISC_PACKAGE_MGRUSER} sudo echo enabled passwordless sudo-ing for${ISC_PACKAGE_MGRUSER}# create dev directoryWORKDIR /opt/irisapp
RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp
USER ${ISC_PACKAGE_MGRUSER}
# Copy source files to imageCOPY . /opt/irisapp
# load class testRUN iris start IRIS \
&& iris session IRIS < /opt/irisapp/iris.script.test \
&& iris stop IRIS quietly
# load class supply RUN iris start IRIS \
&& iris session IRIS < /opt/irisapp/iris.script.supply \
&& iris stop IRIS quietly
car ici, vous demarrez deux fois iris dans deux layers differents, vous allez avoir une image plus volumineuse et peut etre des confics aux niveaux des droits dans les bases de données.
Bonjour Jules,
Question très intéressante.
Sinon, une autre idée peut etre que plutot utiliser la surcharge de méthode pour l'audit, tu pourrais utiliser une macro comme ceci (l'idée me vient d'HealthShare):
ROUTINE XXXX.TraceHelper [Type=INC]
#def1Arg XXXXTRACE(%args) DO:..SendRequestAsync(%args)
Apres tu peux utiliser la macro XXXXTRACE dans tes méthodes pour faire l'audit.
exemple :
Include XXXX.TraceHelper
Class XXXX.OUTILS.BS.ComplexMap.FTP Extends (EnsLib.RecordMap.Service.ComplexBatchFTPService)
{
Parameter ADAPTER = "EnsLib.RecordMap.Service.FileServiceAdapter";
Method OnProcessInput(pInput As %RegisteredObject, Output pOutput As %RegisteredObject) As %Status
{
$$$XXXXTRACE("MyAudditTarget","MyauditMessage",0)
Quit $$$OK
}
}
Cordialement,
Bonjour @Jean-Charles.Cano ,
Pour le passage d'un stream à un autre, j'éviterai d'utiliser la fonction Write si vous ne bouclez pas sur le stream d'entrée.
En effet, la fonction Write fonctionne par chunks, donc si vous n'avez pas lu tout le stream d'entrée, vous risquez de ne pas avoir tout écrit dans le stream de sortie.
Comme vous utilisez la classe Ens.StreamContainer, vous pouvez utiliser le constructeur qui prend en paramètre un stream d'entrée et qui copie le contenu complet du stream d'entrée dans la variable de Stream du StreamContainer.
Method OnProcessInput(pInput As %RegisteredObject, Output pOutput As %RegisteredObject) As %Status
{
Set sc = $$$OK
set res = ##class(Ens.StringResponse).%New()
set request = ##class(%Net.HttpRequest).%New()
set response = ##class(%Net.HttpResponse).%New()
set request.Https = 1
set request.Server = ..ServerAddress
set request.Port = ..Port
set request.SSLConfiguration = ..SSLConfiguration
Try {
set url = ..Path _ "/exportArticles_"_$ZDATE($HOROLOG,8)_".csv"
set status = request.Get(url)
$$$TRACE("request.HttpResponse.Data :"_request.HttpResponse.Data)
#; Commented code to show the difference between the two methods
#; set content = ##class(Ens.StreamContainer).%New()
#; set stream = ##class(%Stream.GlobalCharacter).%New()
#; do stream.Write(request.HttpResponse.Data)
#; Recommended method
set content = ##class(Ens.StreamContainer).%New(request.HttpResponse.Data)
#; Other methods by looping on the stream
#; set content = ##class(Ens.StreamContainer).%New()
#; set stream = ##class(%Stream.GlobalCharacter).%New()
#; while 'request.HttpResponse.Data.AtEnd {
#; set stream.Write(request.HttpResponse.Data.Read())
#; }
#; set content.Stream = stream
$$$TRACE("sc : " _ request.HttpResponse.StatusCode)
#; Old code
#; $$$TRACE("stream size:"_stream.Size)
#; set content.Stream = stream
#; $$$TRACE("stream :"_stream.Read(1000))
#; New code
$$$TRACE("content.Stream.Size :"_content.Stream.Size)
$$$TRACE("content.Stream :"_content.Stream.Read(1000))
set sc = ..SendRequestSync(..TargetConfigNames, content)
}
Catch ex {
set status= ex.AsStatus()
$$$TRACE("erreur : "_status)
}
set result = request.HttpResponse.StatusCode
if (result '= 200) {
$$$TRACE("status: "_ result)
}
return $$$OK
}
Ensuite pour la partie écriture avec l'adapter FTP,vous pouvez utiliser la methode PutStream de l'adapter FTP.
Class SupplyChain.exportArticleHaby Extends Ens.BusinessOperation
{
Property Adapter As EnsLib.FTP.OutboundAdapter;
Parameter ADAPTER = "EnsLib.FTP.OutboundAdapter";
Parameter INVOCATION = "Queue";
Method putFileStream(pRequest As Ens.StreamContainer, Output pResponse As Ens.Response) As %Status
{
$$$TRACE("pRequest : "_ pRequest)
Try {
set fileName = "exportArticles_"_$ZDATE($HOROLOG,8)_".csv"
set esc = ..Adapter.PutStream(fileName, pRequest.Stream)
}
Catch ex {
$$$TRACE("statusCode: " _ esc)
Set tSC=ex.AsStatus()
}
return $$$OK
}
XData MessageMap
{
<MapItems>
<MapItem MessageType="Ens.StreamContainer">
<Method>putFileStream</Method>
</MapItem>
</MapItems>
}
}
Bonjour,
Pour compléter la réponse de Lorenzo, il y aussi les librairies suivantes :
Ou encore utiliser du code python comme car vous utilisez iris 2021.2+:
Class ZIP.demo Extends%RegisteredObject
{
ClassMethod Demo(pFileName As%String) As%Status
{
// Read a zip file into a streamset zipStream = ##class(%Stream.FileBinary).%New()
// Link the stream to the filedo zipStream.LinkToFile(pFileName)
// Call the unzip methodset sc = ##class(ZIP.demo).UnzipStream(zipStream, "/tmp/unzip")
Quit sc
}
ClassMethod UnzipStream(
pZipStream As%Stream.GlobalBinary,
pDestDir As%String) As%Status
{
// Import python lib unzipset unzip = ##class(%SYS.Python).Import("zipfile")
// Write the stream to a temporary fileset tZipStream = ##class(%Stream.FileBinary).%New()
do tZipStream.LinkToFile("/tmp/zipfile.zip")
do tZipStream.CopyFromAndSave(pZipStream)
// Create a new zip objectset zip = unzip.ZipFile("/tmp/zipfile.zip")
// Extract the zip filedo zip.extractall(pDestDir)
// Close the zip filedo zip.close()
Quit$$$OK
}
}
Salut,
Pour le moment le langage parser objectscript permet de formater les fichiers avec la convention de nommage PascaleCase pour les commandes de ligne.
Example :
d..SomeThing()
set toto="titi"for value = "Red","Green","Blue" {
Write value, !
}Apres format :
Do..SomeThing()
Set toto="titi"For value = "Red","Green","Blue" {
Write value, !
}L'indentation n'est pas encore pris en compte.
Tu peux faire une demande d'enhancement ici :
https://github.com/intersystems-community/vscode-objectscript/issues
Je viens de faire la demande :
https://github.com/intersystems-community/vscode-objectscript/issues/12…
Qu'entendez-vous par "éviter toute violation de sécurité"? Quelle violation de sécurité essayez-vous d'éviter? Créer une connexion à IRIS n'est pas une violation de sécurité.
Vous pouvez spécifier l'utilisateur et les rôles dans la chaîne de connexion, vous pouvez donc limiter l'accès à la base de données à ce qui est nécessaire pour la tâche en cours.
Bonjour,
Je pense que c'est possible, cependant je n'ai pas encore eu l'occasion de le faire.
L'idée est la suivante :
Creer votre modèle Django en utilisant les classes Python qui vont bien.
example :
class MyModel(models.Model):
# … fields …
class Meta:
managed = False # No database creation or deletion operations
db_table = 'MyTable'
Note : il faut bien mettre managed = False pour éviter que Django ne crée la table.
Ou alors vous pouvez utiliser la commande django inspectdb pour générer le modèle Django à partir de votre base de données.
python3 manage.py inspectdb
ou encore
python3 manage.py inspectdb > app_name/models.py
wow, c'est cool ca, je connaissais :
Do obj.%Set(sqlFieldName, property, "stream")mais pas :
Do obj.%Set(sqlFieldName, property, "stream>base64")merci pour l'astuce :)
Vous pouvez utiliser Django pour créer des API sur votre base de données.
Les options avec inspectdb ou la création manuelle de modèles sont possibles et ne dupliqueront pas votre base de données.
Elles sont là pour creer un mapping entre votre base de données et des objets Python (les modèles Django). Vous etes donc dans un contexte "MVC" (en fait MTV pour Model Template View si vous utilisez Django en tant que framework web).
Si vous utilisez uniquement Django pour créer des API, vous n'avez pas besoin de templates et de vues, mais vous pouvez utiliser les modèles Django pour créer des objets Python qui représentent vos tables de base de données et donc utiliser les capacités d'ORM (Object Relational Mapping) de Django pour manipuler vos données.
Bonjour,
Pour activer la connexion sans mot de passe à partir d'un compte OS de la machine, il faut configurer le service "%Service_Terminal" comme ceci :
.png)
Ensuite "%Service_Terminal" :
.png)
Pour finir s'assurer que "Operating system" est activé
.png)
yes, sur windows c'est "%Service_console"
https://docs.intersystems.com/iris20232/csp/docbook/DocBook.UI.Page.cls…
Pour information :
Ce depot git fait exatement ce que vous chercher à faire.
Il implemente `djangorestframework` pour des tables pré-existante.
Bonjour,
Pour se connecter à IRIS, il est recommandé d'utiliser un login/password. A ma connaissance, il n'y a pas de moyen de se connecter avec des certificats.
Pour se connecter avec un login/password dans le cas d'une connexion à IRIS en TCP, il est recommandé d'utiliser des variables d'environnement.
Example en python avec le module sqlachemy:
import os
from sqlalchemy import create_engine,text
engine = create_engine(
"iris://",
connect_args={
"hostname": os.environ.get("IRIS_HOST", "localhost"),
"port": os.environ.get("IRIS_PORT", 1972),
"username": os.environ.get("IRIS_USERNAME", "SuperUser"),
"password": os.environ.get("IRIS_PASSWORD", "SYS"),
"namespace": os.environ.get("IRIS_DATABASE", "USER"),
},
)
with engine.connect() as conn:
result = conn.execute(text("SELECT 1"))
print(result.fetchall())
Le cas d'embedded Python est un peu différent car la connexion ne se fait pas par TCP, la connexion se fait par "shared memory".
La connexion dans ce cas est définie par le service "%Service_CallIn" (pour information, les connexions TCP sont définies par le service "%Service_Bindings").
Regardons maintenant les possibilités de connexion offert par le service "%Service_CallIn".
Dans votre cas, peut etre que Operating System est la meilleure solution. Kerberos est aussi une bonne solution mais il faut que votre environnement soit configuré pour.
Pour plus d'information, je vous invite à suivre la discution suivante :
Bonjour,
Les versions LTS d'iris sont les versions en XXXX.1.
Nous appelons ces versions des Extended Maintenance (EM)
Les versions qui ne finissent pas par un 1 sont des Continus Delivery
Plus d'information sur ce post :
https://community.intersystems.com/post/updates-our-release-cadence
Ici pour suivre toutes les versions publiées ainsi que les releases notes:
Bonjour @Moussa SAMB
Je viens de creer un projet example qui permet de se connecter à un server mail type imap en oauth2 :
https://github.com/grongierisc/iris-imap-python-adaptor
Si ca t'intéresse, je peux te le présenter en détail et l'améliorer pour qu'il corresponde à tes besoins.
Super article, en plus avec une exclusivité en langue française :)
Ça me rappel des souvenir d'un projet ou nous avions construit une machine à état : https://developer.mozilla.org/fr/docs/Glossary/State_machine
A l'époque, les messages queues n'existaient pas et ton tuto non plus d’ailleurs ;) ça nous aurait bien aidé.
Pense le compléter avec un exemple appliqué aux websocket, j'ai l'impression que ça s'y prête bien.
Bonjour Cyril,
Je n'ai pas encore été au bout de l'exercice, ce pendant, je vais vous partager mon avancé sur ce sujet :
Avez-vous vérifié que le deamon snmpd etait bien installé et configuré sur votre instance docker ?
Par defaut, il n'est pas installé, il faut donc l'installer et le configurer.
Exemple d'un dockerfile pour installer snmpd :
ARG IMAGE=intersystemsdc/iris-community:latest
FROM $IMAGE
WORKDIR /irisdev/app
USER root
RUN apt-get update && apt-get install -y \
nano \
snmpd \
snmp \
sudo && \
/bin/echo -e ${ISC_PACKAGE_MGRUSER}\\tALL=\(ALL\)\\tNOPASSWD: ALL >> /etc/sudoers && \
sudo -u ${ISC_PACKAGE_MGRUSER} sudo echo enabled passwordless sudo-ing for ${ISC_PACKAGE_MGRUSER}
COPY snmpd.conf /etc/snmp/snmpd.conf
USER ${ISC_PACKAGE_MGRUSER}
Exemple d'un snmpd.conf :
###############################################################################
#
# snmpd.conf:
# An example configuration file for configuring the NET-SNMP agent with Cache.
#
# This has been used successfully on Red Hat Enterprise Linux and running
# the snmpd daemon in the foreground with the following command:
#
# /usr/sbin/snmpd -f -L -x TCP:localhost:705 -c./snmpd.conf
#
# You may want/need to change some of the information, especially the
# IP address of the trap receiver of you expect to get traps. I've also seen
# one case (on AIX) where we had to use the "-C" option on the snmpd command
# line, to make sure we were getting the correct snmpd.conf file.
#
###############################################################################
###########################################################################
# SECTION: System Information Setup
#
# This section defines some of the information reported in
# the "system" mib group in the mibII tree.
# syslocation: The [typically physical] location of the system.
# Note that setting this value here means that when trying to
# perform an snmp SET operation to the sysLocation.0 variable will make
# the agent return the "notWritable" error code. IE, including
# this token in the snmpd.conf file will disable write access to
# the variable.
# arguments: location_string
syslocation "System Location"
# syscontact: The contact information for the administrator
# Note that setting this value here means that when trying to
# perform an snmp SET operation to the sysContact.0 variable will make
# the agent return the "notWritable" error code. IE, including
# this token in the snmpd.conf file will disable write access to
# the variable.
# arguments: contact_string
syscontact "Your Name"
# sysservices: The proper value for the sysServices object.
# arguments: sysservices_number
sysservices 76
###########################################################################
# SECTION: Agent Operating Mode
#
# This section defines how the agent will operate when it
# is running.
# master: Should the agent operate as a master agent or not.
# Currently, the only supported master agent type for this token
# is "agentx".
#
# arguments: (on|yes|agentx|all|off|no)
master agentx
agentXSocket tcp:localhost:705
###########################################################################
# SECTION: Trap Destinations
#
# Here we define who the agent will send traps to.
# trapsink: A SNMPv1 trap receiver
# arguments: host [community] [portnum]
trapsink localhost public
###############################################################################
# Access Control
###############################################################################
# As shipped, the snmpd demon will only respond to queries on the
# system mib group until this file is replaced or modified for
# security purposes. Examples are shown below about how to increase the
# level of access.
#
# By far, the most common question I get about the agent is "why won't
# it work?", when really it should be "how do I configure the agent to
# allow me to access it?"
#
# By default, the agent responds to the "public" community for read
# only access, if run out of the box without any configuration file in
# place. The following examples show you other ways of configuring
# the agent so that you can change the community names, and give
# yourself write access to the mib tree as well.
#
# For more information, read the FAQ as well as the snmpd.conf(5)
# manual page.
#
####
# First, map the community name "public" into a "security name"
# sec.name source community
com2sec notConfigUser default public
####
# Second, map the security name into a group name:
# groupName securityModel securityName
group notConfigGroup v1 notConfigUser
group notConfigGroup v2c notConfigUser
####
# Third, create a view for us to let the group have rights to:
# Make at least snmpwalk -v 1 localhost -c public system fast again.
# name incl/excl subtree mask(optional)
# access to 'internet' subtree
view systemview included .1.3.6.1
# access to Cache MIBs Caché and Ensemble
view systemview included .1.3.6.1.4.1.16563.1
view systemview included .1.3.6.1.4.1.16563.2
####
# Finally, grant the group read-only access to the systemview view.
# group context sec.model sec.level prefix read write notif
access notConfigGroup "" any noauth exact systemview none none
Ensuite, il faut lancer le deamon snmpd :
sudo service snmpd start
Sur iris, il faut ensuite configurer le snmp agent :
%SYS> w $$start^SNMP()
Avec toutes ces étapes, vous devriez pouvoir récupérer des informations via snmp.
snmpwalk -m ALL -v 2c -c public localhost .1.3.6.1.4.1.16563.1.1.1.1
C'est là ou je bloque pour le moment, je n'arrive pas à récupérer les informations d'IRIS.
Cependant, le service snmpd est bien lancé et fonctionnel ainsi que le snmp agent.
Pour plus d'informations, je vous invite à lire les articles suivants :
Bonjour,
Effectivement, le service EnsLib.SQL.Service.GenericService est un service de type "Business Service" qui va générer un message pour chaque ligne de résultat de la requête SQL. Ce service est donc adapté pour des requêtes qui retournent un nombre limité de lignes.
Je pense que tu vas devoir passer par du code custom.
Voici un exemple en Python qui est relativement simple à mettre en oeuvre.
Le bs :
from grongier.pex import BusinessService
import pandas as pd
from sqlalchemy import create_engine
from .msg import SQLMessage
class SQLService(BusinessService):
def __init__(self, **kwargs):
self.sql = None
self.conn = None
self.target = None
def on_init(self):
if not hasattr(self, 'sql'):
raise Exception('Missing sql attribute')
if not hasattr(self, 'conn'):
raise Exception('Missing conn attribute')
if not hasattr(self, 'target'):
raise Exception('Missing target attribute')
self.engine = create_engine(self.conn)
# raise an error if cannot connect to the database
self.engine.connect()
def get_adapter_type():
"""
Name of the registred Adapter
"""
return "Ens.InboundAdapter"
def on_process_input(self, message_input):
# create a dataframe from the sql query
df = pd.read_sql(self.sql, self.engine)
# create a message
message = SQLMessage(dataframe=df)
# send the message to the target
self.send_request_sync(self.target, message)
return
Ici on utilise la force de pandas pour créer un dataframe à partir du résultat de la requête SQL. On crée ensuite un message qui contient le dataframe et on l'envoie au target.
La configuration est faite à partir de propriétés suivantes :
Le message :
from grongier.pex import Message
from dataclasses import dataclass
from pandas.core.frame import DataFrame
@dataclass
class SQLMessage(Message):
dataframe: DataFrame = None
Le message qui contient le dataframe.
La target qui permet de créer le fichier csv :
from grongier.pex import BusinessOperation
from .msg import SQLMessage
import pandas as pd
class CSVOperation(BusinessOperation):
def __init__(self, **kwargs):
self.filename = None
def on_init(self):
if not hasattr(self, 'filename'):
raise Exception('Missing filename attribute')
def on_sql_message(self, message_input: SQLMessage):
# get the dataframe from the message
df = message_input.dataframe
# create a csv file
df.to_csv(self.filename, index=False)
return
La configuration est faite à partir du fichier settings.py :
from sqltocsv import bo,bs
import os
CLASSES = {
'Python.Bs.SQLService': bs.SQLService,
'Python.Bo.CSVOperation': bo.CSVOperation
}
db_user = os.environ.get('POSTGRES_USER', 'DemoData')
db_password = os.environ.get('POSTGRES_PASSWORD', 'DemoData')
db_host = os.environ.get('POSTGRES_HOST', 'db')
db_port = os.environ.get('POSTGRES_PORT', '5432')
db_name = os.environ.get('POSTGRES_DB', 'DemoData')
PRODUCTIONS = [{
"Python.Production": {
"@Name": "Python.Production",
"@LogGeneralTraceEvents": "false",
"Description": "",
"ActorPoolSize": "2",
"Item": [
{
"@Name": "Python.Bs.SQLService",
"@Category": "",
"@ClassName": "Python.Bs.SQLService",
"@PoolSize": "1",
"@Enabled": "true",
"@Foreground": "false",
"@Comment": "",
"@LogTraceEvents": "false",
"@Schedule": "",
"Setting": {
"@Target": "Host",
"@Name": "%settings",
"#text": "sql=select * from formation\nconn=postgresql://"+db_user+":"+db_password+"@"+db_host+":"+db_port+"/"+db_name+"\ntarget=Python.Bo.CSVOperation"
}
},
{
"@Name": "Python.Bo.CSVOperation",
"@Category": "",
"@ClassName": "Python.Bo.CSVOperation",
"@PoolSize": "1",
"@Enabled": "true",
"@Foreground": "false",
"@Comment": "",
"@LogTraceEvents": "false",
"@Schedule": "",
"Setting": {
"@Target": "Host",
"@Name": "%settings",
"#text": "filename=/tmp/export.csv"
}
}
]
}
}]
On utilise les variables d'environnement pour la connexion à la base de données.
Tu as l'exemple complet ici :
https://github.com/grongierisc/formation-template-python/tree/demo_sqltodb
Je laisse un autre membre de la communauté répondre avec une solution en ObjectScript.