#Melhores Práticas

0 Seguidores · 26 Postagens

Recomendações de melhores práticas sobre como desenvolver, testar, implantar e gerenciar melhor as soluções nas Plataformas de Dados InterSystems. 

Artigo Danusa Calixto · Abr. 16, 2024 26m read

1. interoperability-embedded-python

Esta prova de conceito busca mostrar como o framework de interoperabilidade do iris pode ser usado com o embedded python.

1.1. Índice

1.2. Exemplo

from grongier.pex import BusinessOperation,Message

class MyBusinessOperation(BusinessOperation):
    
    def on_init(self):
        #Esse método é chamado quando o componente está se tornando ativo na produção

        self.log_info("[Python] ...MyBusinessOperation:on_init() is called")

        return

    def on_teardown(self):
        #Esse método é chamado quando o componente está se tornando inativo na produção

        self.log_info("[Python] ...MyBusinessOperation:on_teardown() is called")

        return

    def on_message(self, message_input:MyRequest):
        #É chamado do serviço/processo/operação, a mensagem é do tipo MyRequest com a propriedade request_string

        self.log_info("[Python] ...MyBusinessOperation:on_message() is called with message:"+message_input.request_string)

        response = MyResponse("...MyBusinessOperation:on_message() echos")

        return response

@dataclass
class MyRequest(Message):

    request_string:str = None

@dataclass
class MyResponse(Message):

    my_string:str = None

1.3. Registrar um componente

Graças ao método grongier.pex.Utils.register_component():

Inicie um shell do embedded python:

/usr/irissys/bin/irispython

Em seguida, use esse método de classe para adicionar uma classe do python à lista de componentes para interoperabilidade.

from grongier.pex import Utils

Utils.register_component(<ModuleName>,<ClassName>,<PathToPyFile>,<OverWrite>,<NameOfTheComponent>)

Por exemplo:

from grongier.pex import Utils

Utils.register_component("MyCombinedBusinessOperation","MyCombinedBusinessOperation","/irisdev/app/src/python/demo/",1,"PEX.MyCombinedBusinessOperation")

Isso é um truque, e não serve para produção.

2. Demonstração

A demonstração pode ser encontrada em src/python/demo/reddit/ e é composta de:

  • Um arquivo adapter.py com um RedditInboundAdapter que, dado um serviço, buscará postagens recentes do Reddit.

  • Um arquivo bs.py com três services que faz a mesma coisa: ele chamará nosso Process e enviará a postagem do Reddit. Um funciona sozinho, um usa o RedditInBoundAdapter que mencionamos antes e o último usa um inbound adapter do Reddit codificado em ObjectScript.

  • Um arquivo bp.py com um processo FilterPostRoutingRule que analisará nossas postagens do Reddit e as enviará para nossas operations se tiverem determinadas palavras.

  • Um arquivo bo.py com:

    • Duas operações de e-mail que enviarão um e-mail para uma empresa específica dependendo das palavras analisadas antes. Uma funciona sozinha e a outra funciona com um OutBoundAdapter.
    • Duas operações de arquivo que escreverão em um arquivo de texto dependendo das palavras analisadas antes. Uma funciona sozinha e outra funciona com um OutBoundAdapter.

Novo trace json para mensagens nativas do python: json-message-trace

3. Pré-requisitos

Verifique se você tem o git e o Docker desktop instalados.

4. Instalação

4.1. Com Docker

Faça o git pull/clone do repositório em qualquer diretório local

git clone https://github.com/grongierisc/interpeorability-embedded-python

Abra o terminal nesse diretório e execute:

docker-compose build

Execute o contêiner IRIS com seu projeto:

docker-compose up -d

4.2. Sem Docker

Instale o grongier_pex-1.2.4-py3-none-any.whl na sua instância iris local:

/usr/irissys/bin/irispython -m pip install grongier_pex-1.2.4-py3-none-any.whl

Em seguida, carregue as classes ObjectScript:

do $System.OBJ.LoadDir("/opt/irisapp/src","cubk","*.cls",1)

4.3. Com ZPM

zpm "install pex-embbeded-python" 

4.4. Com PyPI

pip3 install iris_pex_embedded_python

Importe as classes ObjectScript, abra um shell do embedded python e execute:

from grongier.pex import Utils
Utils.setup()

4.4.1. Problemas conhecidos

Se o módulo não estiver atualizado, remova a versão antiga:

pip3 uninstall iris_pex_embedded_python

ou remova manualmente a pasta grongier em <iris_installation>/lib/python/

ou force a instalação com o pip:

pip3 install --upgrade iris_pex_embedded_python --target <iris_installation>/lib/python/

5. Como executar a amostra

5.1. Contêineres Docker

Para ter acesso às imagens da InterSystems, é necessário acessar o seguinte URL: http://container.intersystems.com. Depois de se conectar com as credenciais da InterSystems, obtenha a senha para se conectar ao registro. No complemento VSCode do docker, na guia de imagens, ao pressionar "connect registry" e inserir o mesmo url de antes (http://container.intersystems.com) como um registro genérico, será solicitado as credenciais. O login é o habitual, mas a senha é a obtida do site.

Em seguida, será possível criar e compor os contêineres (com os arquivos docker-compose.yml e Dockerfile fornecidos).

5.2. Portal de Gerenciamento e VSCode

Esse repositório está pronto para o VS Code.

Abra a pasta interoperability-embedeed-python clonada localmente no VS Code.

Se solicitado (canto inferior direito), instale as extensões recomendadas.

IMPORTANTE: quando solicitado, reabra a pasta dentro do contêiner, para que você possa usar os componentes do python dentro dele. Na primeira vez que você fizer isso, o contêiner pode levar vários minutos para ficar pronto.

Ao abrir a pasta remota, você permite que o VS Code e quaisquer terminais abertos dentro dele usem os componentes do python dentro do contêiner. Configure-os para usar /usr/irissys/bin/irispython

PythonInterpreter

5.3. Abra a produção

Para abrir a produção, você pode acessar a [produção] (http://localhost:52773/csp/irisapp/EnsPortal.ProductionConfig.zen?PRODUCTION=PEX.Production).
Você também pode clicar na parte inferior no botão 127.0.0.1:52773[IRISAPP], selecionar Open Management Portal(Abrir Portal de Gerenciamento), clicar nos menus [Interoperability] e [Configure] e, depois, em [productions] e [Go].

A produção já tem uma amostra de código.

Aqui podemos ver a produção e nossos serviços e operações de python puro: interop-screenshot


Novo trace json para mensagens nativas do python: json-message-trace

6. O que está dentro do repositório

6.1. Dockerfile

Um dockerfile que instala algumas dependências do python (pip, venv) e sudo no contêiner para conveniência. Em seguida, ele cria o diretório dev e copia nele esse repositório git.

Ele inicia o IRIS e ativa %Service_CallIn para o Shell do Python. Use o docker-compose.yml relacionado para configurar facilmente parâmetros adicionais, como número da porta e onde você mapeia chaves e hospeda pastas.

Esse dockerfile termina com a instalação dos requisitos para os módulos do python.

Use o arquivo .env/ para ajustar o dockerfile usado em docker-compose.

6.2. .vscode/settings.json

Arquivo de configurações para você programar imediatamente no VSCode com o [plugin ObjectScript do VSCode] (https://marketplace.visualstudio.com/items?itemName=daimor.vscode-objectscript)

6.3. .vscode/launch.json

Arquivo de configurações se você quiser depurar com o ObjectScript do VSCode

Leia sobre todos os arquivos neste artigo

6.4. .vscode/extensions.json

Arquivo de recomendação para adicionar extensões se você quiser executar com o VSCode no contêiner.

Mais informações aqui

Archiecture

Isso é muito útil para trabalhar com o embedded python.

6.5. src folder

src
├── Grongier
│   └── PEX // Classes ObjectScript que envolvem código em python
│       ├── BusinessOperation.cls
│       ├── BusinessProcess.cls
│       ├── BusinessService.cls
│       ├── Common.cls
│       ├── Director.cls
│       ├── InboundAdapter.cls
│       ├── Message.cls
│       ├── OutboundAdapter.cls
│       ├── Python.cls
│       ├── Test.cls
│       └── _utils.cls
├── PEX // Alguns exemplos de classes envolvidas
│   └── Production.cls
└── python
    ├── demo // código em python real para executar essa demonstração
    |   `-- reddit
    |       |-- adapter.py
    |       |-- bo.py
    |       |-- bp.py
    |       |-- bs.py
    |       |-- message.py
    |       `-- obj.py
    ├── dist // Wheel usado para implementar componentes de interoperabilidade do python
    │   └── grongier_pex-1.2.4-py3-none-any.whl
    ├── grongier
    │   └── pex // Classes helper para implementar componentes de interoperabilidade
    │       ├── _business_host.py
    │       ├── _business_operation.py
    │       ├── _business_process.py
    │       ├── _business_service.py
    │       ├── _common.py
    │       ├── _director.py
    │       ├── _inbound_adapter.py
    │       ├── _message.py
    │       ├── _outbound_adapter.py
    │       ├── __init__.py
    │       └── _utils.py
    └── setup.py // configuração para criar o wheel

7. Como funciona

7.1. Arquivo __init__.py

Esse arquivo nos permite criar as classes para importar no código.
Ele obtém as classes de vários arquivos vistos antes e as transforma em classes callable. Assim, quando você quiser criar uma operação de negócios, por exemplo, pode só executar:

from grongier.pex import BusinessOperation

7.2. Classe common

A classe common não deve ser chamada pelo usuário. Ela define quase todas as outras classes.
Essa classe define:

on_init: esse método é chamado quando o componente é inicializado.
Use o método on_init() para inicializar qualquer estrutura necessária para o componente.

on_tear_down: é chamado antes de encerrar o componente.
Use para liberar qualquer estrutura.

on_connected: esse método é chamado quando o componente é conectado ou reconectado após ser desconectado.
Use o método on_connected() para inicializar qualquer estrutura necessária para o componente.

log_info: grava uma entrada de log do tipo "info". As entradas de log podem ser visualizadas no portal de gerenciamento.

log_alert: grava uma entrada de log do tipo "alert". As entradas de log podem ser visualizadas no portal de gerenciamento.

log_warning: grava uma entrada de log do tipo "warning". As entradas de log podem ser visualizadas no portal de gerenciamento.

log_error: grava uma entrada de log do tipo "error". As entradas de log podem ser visualizadas no portal de gerenciamento.

7.3. Classe business_host

A classe de host de negócios não deve ser chamada pelo usuário. É a classe base para todas as classes de negócios.
Essa classe define:

send_request_sync: envia a mensagem específica à operação ou ao processo de negócios alvo de maneira síncrona.
Parâmetros:

  • target: uma string que especifica o nome da operação ou do processo de negócios a receber a solicitação.
    O alvo é o nome do componente conforme especificado na propriedade Item Name na definição da produção, e não o nome da classe do componente.
  • request: especifica a mensagem a enviar ao alvo. A solicitação é uma instância de uma classe que é IRISObject ou subclasse da classe Message.
    Se o alvo é um componente ObjectScript integrado, você deve usar a classe IRISObject. A classe IRISObject permite que o framework PEX converta a mensagem para uma classe compatível com o alvo.
  • timeout: um inteiro opcional que especifica o número de segundos de espera antes de tratar a solicitação de envio como uma falha. O valor padrão é -1, que significa "esperar para sempre".
    description: um parâmetro de string opcional que define uma propriedade da descrição no cabeçalho da mensagem. O padrão é None.

Retorna: o objeto de resposta do alvo.

Gera: TypeError: se a solicitação não é do tipo Message ou IRISObject.


send_request_async: envia a mensagem específica ao processo ou operação de negócios alvo de maneira assíncrona. Parâmetros:

  • target: uma string que especifica o nome da operação ou do processo de negócios a receber a solicitação.
    O alvo é o nome do componente conforme especificado na propriedade Item Name na definição da produção, e não o nome da classe do componente.
  • request: especifica a mensagem a enviar ao alvo. A solicitação é uma instância de IRISObject ou de uma subclasse de Message.
    Se o alvo é um componente ObjectScript integrado, você deve usar a classe IRISObject. A classe IRISObject permite que o framework PEX converta a mensagem para uma classe compatível com o alvo.
  • description: um parâmetro de string opcional que define uma propriedade da descrição no cabeçalho da mensagem. O padrão é None.

Gera: TypeError: se a solicitação não é do tipo Message ou IRISObject.


get_adapter_type: nome do adaptador registrado.

7.4. Classe inbound_adapter

Inbound Adapter no Python é uma subclasse de grongier.pex.InboundAdapter no Python, que herda de todas as funções da classe common.
Essa classe é responsável por receber os dados do sistema externo, validar os dados e enviá-los ao serviço de negócios ao chamar o método process_input de BusinessHost. Essa classe define:

on_task: é chamado pelo framework de produção a intervalos determinados pela propriedade CallInterval do serviço de negócios.
A mensagem pode ter qualquer estrutura que esteja de acordo com o inbound adapter e serviço de negócios.

Exemplo de um inbound adapter (localizado no arquivo src/python/demo/reddit/adapter.py):

from grongier.pex import InboundAdapter
import requests
import iris
import json

class RedditInboundAdapter(InboundAdapter):
    """
    Esse adaptador usa solicitações para buscar postagens self.limit como dados da API Reddit
    antes de chamar o process_input para cada postagem.
    """
    def on_init(self):
        
        if not hasattr(self,'feed'):
            self.feed = "/new/"
        
        if self.limit is None:
            raise TypeError('no Limit field')
        
        self.last_post_name = ""
        
        return 1

    def on_task(self):
        self.log_info(f"LIMIT:{self.limit}")
        if self.feed == "" :
            return 1
        
        tSC = 1
        # Solicitação HTTP
        try:
            server = "https://www.reddit.com"
            request_string = self.feed+".json?before="+self.last_post_name+"&limit="+self.limit
            self.log_info(server+request_string)
            response = requests.get(server+request_string)
            response.raise_for_status()

            data = response.json()
            updateLast = 0

            for key, value in enumerate(data['data']['children']):
                if value['data']['selftext']=="":
                    continue
                post = iris.cls('dc.Reddit.Post')._New()
                post._JSONImport(json.dumps(value['data']))
                post.OriginalJSON = json.dumps(value)
                if not updateLast:
                    self.LastPostName = value['data']['name']
                    updateLast = 1
                response = self.BusinessHost.ProcessInput(post)
        except requests.exceptions.HTTPError as err:
            if err.response.status_code == 429:
                self.log_warning(err.__str__())
            else:
                raise err
        except Exception as err: 
            self.log_error(err.__str__())
            raise err

        return tSC

7.5. Classe outbound_adapter

Outbound Adapter no Python é uma subclasse de grongier.pex.OutboundAdapter no Python, que herda de todas as funções da classe common.
Essa classe é responsável por enviar os dados para o sistema externo.

O Outbound Adapter possibilita à operação ter uma noção dos batimentos cardíacos. Para ativar essa opção, o parâmetro CallInterval do adaptador precisa ser estritamente maior que 0.

image

Exemplo de um outbound adapter (localizado no arquivo src/python/demo/reddit/adapter.py):

class TestHeartBeat(OutboundAdapter):

    def on_keepalive(self):
        self.log_info('beep')

    def on_task(self):
        self.log_info('on_task')

7.6. Classe business_service

Essa classe é responsável por receber os dados do sistema externo e enviá-los aos processos ou operações de negócios na produção.
O serviço de negócios pode usar um adaptador para acessar o sistema externo, que é especificado sobrescrevendo o método get_adaptar_type.
Há três maneiras de implementar um serviço de negócios:

  • Serviço de negócios de sondagem com um adaptador - O framework de produção chama a intervalos regulares o método OnTask() do adaptador, que envia os dados recebidos ao método ProcessInput() do serviço de negócios, que, por sua vez, chama o método OnProcessInput com seu código.

  • Serviço de negócios de sondagem que usa o adaptador padrão - Nesse caso, o framework chama o método OnTask do adaptador padrão sem dados. Em seguida, o método OnProcessInput() realiza o papel do adaptador e é responsável por acessar o sistema externo e receber os dados.

  • Serviço de negócios sem sondagem - O framework de produção não inicia o serviço de negócios. Em vez disso, o código personalizado em um processo longo ou um que é inicializado a intervalos regulares inicia o serviço de negócios ao chamar o método Director.CreateBusinessService().

O serviço de negócios no Python é uma subclasse de grongier.pex.BusinessService no Python, que herda de todas as funções do host de negócios.
Essa classe define:

on_process_input: recebe a mensagem do inbound adapter pelo método ProcessInput e é responsável por encaminhá-la aos processos ou operações de negócios alvo.
Se o serviço de negócios não especifica um adaptador, o adaptador padrão chama esse método sem mensagem e o serviço de negócios é responsável por receber os dados do sistema externo e validá-los. Parâmetros:

  • message_input: uma instância de IRISObject ou subclasse de Message com os dados que o inbound adapter transmite.
    A mensagem pode ter qualquer estrutura que esteja de acordo com o inbound adapter e serviço de negócios.


Exemplo de um serviço de negócios (localizado no arquivo src/python/demo/reddit/bs.py):

from grongier.pex import BusinessService

import iris

from message import PostMessage
from obj import PostClass

class RedditServiceWithPexAdapter(BusinessService):
    """
    This service use our python Python.RedditInboundAdapter to receive post
    from reddit and call the FilterPostRoutingRule process.
    """
    def get_adapter_type():
        """
        Name of the registred Adapter
        """
        return "Python.RedditInboundAdapter"

    def on_process_input(self, message_input):
        msg = iris.cls("dc.Demo.PostMessage")._New()
        msg.Post = message_input
        return self.send_request_sync(self.target,msg)

    def on_init(self):
        
        if not hasattr(self,'target'):
            self.target = "Python.FilterPostRoutingRule"
        
        return

7.7. Classe business_process

Geralmente, contém a maior parte da lógica em uma produção.
Um processo de negócios pode receber mensagens de um serviço, processo ou operação de negócios.
Ele pode modificar a mensagem, convertê-la para um formato diferente ou roteá-la com base no conteúdo dela.
O processo de negócios pode rotear uma mensagem para uma operação ou outro processo de negócios.
Os processos de negócios no Python são uma subclasse de grongier.pex.BusinessProcess no Python, que herda de todas as funções do host de negócios.
Essa classe define:

on_request: processa as solicitações enviadas ao processo de negócios. Uma produção chama esse método quando uma solicitação inicial de um processo de negócios específico chega na fila apropriada e é atribuída a um trabalho em que deve ser executada.
Parâmetros:

  • request: uma instância de IRISObject ou subclasse de Message que contém a mensagem de solicitação enviada ao processo de negócios.

Retorna: Uma instância de IRISObject ou subclasse de Message que contém a mensagem de resposta que esse processo de negócios pode retornar ao componente de produção que enviou a mensagem inicial.


on_response: processa as respostas enviadas ao processo de negócios em resposta às mensagens ele que enviou ao alvo.
Uma produção chama esse método sempre que uma resposta a um processo de negócios específico chega na fila apropriada e é atribuída a um trabalho em que deve ser executada.
Geralmente, isso é uma resposta a uma solicitação assíncrona feita pelo processo de negócios onde o parâmetro responseRequired tem um valor "true".
Parâmetros:

  • request: uma instância de IRISObject ou subclasse de Message que contém a mensagem de solicitação inicial enviada ao processo de negócios.
  • response: uma instância de IRISObject ou subclasse de Message que contém a mensagem de resposta que esse processo de negócios pode retornar ao componente de produção que enviou a mensagem inicial.
  • callRequest: uma instância de IRISObject ou subclasse de Message que contém a solicitação que o processo de negócios enviou ao seu alvo.
  • callResponse: uma instância de IRISObject ou subclasse de Message que contém a resposta de entrada.
  • completionKey: uma string que contém a completionKey especificada no parâmetro completionKey do método SendAsync() de saída.

Retorna: Uma instância de IRISObject ou subclasse de Message que contém a mensagem de resposta que esse processo de negócios pode retornar ao componente de produção que enviou a mensagem inicial.


on_complete: é chamado depois que o processo de negócios recebeu e processou todas as respostas às solicitações que enviou aos alvos.
Parâmetros:

  • request: uma instância de IRISObject ou subclasse de Message que contém a mensagem de solicitação inicial enviada ao processo de negócios.
  • response: uma instância de IRISObject ou subclasse de Message que contém a mensagem de resposta que esse processo de negócios pode retornar ao componente de produção que enviou a mensagem inicial.

Retorna: Uma instância de IRISObject ou subclasse de Message que contém a mensagem de resposta que esse processo de negócios pode retornar ao componente de produção que enviou a mensagem inicial.


Exemplo de um processo de negócios (localizado no arquivo src/python/demo/reddit/bp.py):

from grongier.pex import BusinessProcess

from message import PostMessage
from obj import PostClass

class FilterPostRoutingRule(BusinessProcess):
    """
    This process receive a PostMessage containing a reddit post.
    It then understand if the post is about a dog or a cat or nothing and
    fill the right infomation inside the PostMessage before sending it to
    the FileOperation operation.
    """
    def on_init(self):
        
        if not hasattr(self,'target'):
            self.target = "Python.FileOperation"
        
        return

    def on_request(self, request):

        if 'dog'.upper() in request.post.selftext.upper():
            request.to_email_address = 'dog@company.com'
            request.found = 'Dog'
        if 'cat'.upper() in request.post.selftext.upper():
            request.to_email_address = 'cat@company.com'
            request.found = 'Cat'

        if request.found is not None:
            return self.send_request_sync(self.target,request)
        else:
            return

7.8. Classe business_operation

Essa classe é responsável por enviar os dados a um sistema externo ou local como um banco de dados do iris.
A operação de negócios pode usar opcionalmente um adaptador para processar a mensagem de saída que é especificada sobrescrevendo o método get_adapter_type.
Se a operação de negócios tiver um adaptador, ela usa o adaptador para enviar a mensagem ao sistema externo.
O adaptador pode ser um adaptador PEX, ObjectScript ou python.
A operação de negócios no Python é uma subclasse de grongier.pex.BusinessOperation no Python, que herda de todas as funções do host de negócios.

7.8.1. Sistema de despacho

Em uma operação de negócios, é possível criar qualquer número de funções semelhante ao método on_message que aceitam como argumento uma solicitação tipada como esse my_special_message_method(self,request: MySpecialMessage).

O sistema de despacho analisará automaticamente qualquer solicitação que chegar à operação e despachará as solicitações dependendo do tipo delas. Se o tipo de solicitação não for reconhecido ou não estiver especificado em qualquer função semelhante a on_message, o sistema de despacho a enviará para a função on_message.

7.8.2. Métodos

Essa classe define:

on_message: é chamado quando a operação de negócios recebe uma mensagem de outro componente da produção que não pode ser despachada a outra função.
Geralmente, a operação envia a mensagem ao sistema externo ou a encaminha para um processo ou outra operação de negócios. Se a operação tiver um adaptador, ela usa o método Adapter.invoke() para chamar o método no adaptador que envia a mensagem ao sistema externo. Se a operação estiver encaminhando a mensagem a outro componente da produção, ela usa o método SendRequestAsync() ou SendRequestSync().
Parâmetros:

  • request: uma instância de IRISObject ou subclasse de Message que contém a mensagem de entrada para a operação de negócios.

Retorna: O objeto de resposta

Exemplo de uma operação de negócios (localizada no arquivo src/python/demo/reddit/bo.py):

from grongier.pex import BusinessOperation

from message import MyRequest,MyMessage

import iris

import os
import datetime
import smtplib
from email.mime.text import MIMEText

class EmailOperation(BusinessOperation):
    """
    This operation receive a PostMessage and send an email with all the
    important information to the concerned company ( dog or cat company )
    """

    def my_message(self,request:MyMessage):
        sender = 'admin@example.com'
        receivers = 'toto@example.com'
        port = 1025
        msg = MIMEText(request.toto)

        msg['Subject'] = 'MyMessage'
        msg['From'] = sender
        msg['To'] = receivers

        with smtplib.SMTP('localhost', port) as server:
            server.sendmail(sender, receivers, msg.as_string())
            print("Successfully sent email")

    def on_message(self, request):

        sender = 'admin@example.com'
        receivers = [ request.to_email_address ]


        port = 1025
        msg = MIMEText('This is test mail')

        msg['Subject'] = request.found+" found"
        msg['From'] = 'admin@example.com'
        msg['To'] = request.to_email_address

        with smtplib.SMTP('localhost', port) as server:
            
            # server.login('username', 'password')
            server.sendmail(sender, receivers, msg.as_string())
            print("Successfully sent email")

Se essa operação for chamada usando uma mensagem MyRequest, a função my_message será chamada graças ao dispatcher. Caso contrário, a função on_message será chamada.

7.9. Classe director

A classe Director é usada para serviços de negócios sem sondagem, ou seja, serviços de negócios que não são chamados automaticamente pelo framework da produção (pelo inbound adapter) no intervalo da chamada.
Em vez disso, esses serviços de negócios são criados por um aplicativo personalizado ao chamar o método Director.create_business_service().
Essa classe define:

create_business_service: esse método inicia o serviço de negócios especificado.
Parâmetros:

  • connection: um objeto IRISConnection que especifica a conexão a uma instância IRIS para Java.
  • target: uma string que especifica o nome do serviço de negócios na definição da produção.

Retorna: um objeto que contém uma instância de IRISBusinessService

start_production: esse método inicia a produção.
Parâmetros:

  • production_name: uma string que especifica o nome da produção a iniciar.

stop_production: esse método interrompe a produção.
Parâmetros:

  • production_name: uma string que especifica o nome da produção a interromper.

restart_production: esse método reinicia a produção.
Parâmetros:

  • production_name: uma string que especifica o nome da produção a reiniciar.

list_productions: esse método retorna um dicionário de nomes das produções que estão sendo executadas no momento.

7.10. Os objects

Vamos usar dataclass para armazenar informações em nossas mensagens em um arquivo obj.py.

Exemplo de um objeto (localizado no arquivo src/python/demo/reddit/obj.py):

from dataclasses import dataclass

@dataclass
class PostClass:
    title: str
    selftext : str
    author: str
    url: str
    created_utc: float = None
    original_json: str = None

7.11. As messages

As mensagens conterão um ou mais objetos, localizados no arquivo obj.py.
Mensagens, solicitações e respostas herdam da classe grongier.pex.Message.

Essas mensagens nos permitem transferir informações entre qualquer serviço/processo/operação de negócios.

Exemplo de uma mensagem (localizada no arquivo src/python/demo/reddit/message.py):

from grongier.pex import Message

from dataclasses import dataclass

from obj import PostClass

@dataclass
class PostMessage(Message):
    post:PostClass = None
    to_email_address:str = None
    found:str = None

WIP Vale destacar que é necessário usar tipos ao definir um objeto ou uma mensagem.

7.12. Como registrar um componente

Você pode registrar um componente no iris de várias formas:

  • Somente um componente com register_component
  • Todos os componentes em um arquivo com register_file
  • Todos os componentes em um arquivo com register_folder

7.12.1. register_component

Inicie um shell do embedded python:

/usr/irissys/bin/irispython

Em seguida, use esse método de classe para adicionar um novo arquivo py à lista de componentes para interoperabilidade.

from grongier.pex import Utils
Utils.register_component(<ModuleName>,<ClassName>,<PathToPyFile>,<OverWrite>,<NameOfTheComponent>)

Por exemplo:

from grongier.pex import Utils
Utils.register_component("MyCombinedBusinessOperation","MyCombinedBusinessOperation","/irisdev/app/src/python/demo/",1,"PEX.MyCombinedBusinessOperation")

7.12.2. register_file

Inicie um shell do embedded python:

/usr/irissys/bin/irispython

Em seguida, use esse método de classe para adicionar um novo arquivo py à lista de componentes para interoperabilidade.

from grongier.pex import Utils
Utils.register_file(<File>,<OverWrite>,<PackageName>)

Por exemplo:

from grongier.pex import Utils
Utils.register_file("/irisdev/app/src/python/demo/bo.py",1,"PEX")

7.12.3. register_folder

Inicie um shell do embedded python:

/usr/irissys/bin/irispython

Em seguida, use esse método de classe para adicionar um novo arquivo py à lista de componentes para interoperabilidade.

from grongier.pex import Utils
Utils.register_folder(<Path>,<OverWrite>,<PackageName>)

Por exemplo:

from grongier.pex import Utils
Utils.register_folder("/irisdev/app/src/python/demo/",1,"PEX")

7.12.4. migrate

Inicie um shell do embedded python:

/usr/irissys/bin/irispython

Em seguida, use esse método estático para migrar o arquivo de configurações para o framework iris.

from grongier.pex import Utils
Utils.migrate()

7.12.4.1. Arquivo setting.py

Esse arquivo é usado para armazenar as configurações dos componentes de interoperabilidade.

Ele tem duas seções:

  • CLASSES: essa seção é usada para armazenar as classes dos componentes de interoperabilidade.
  • PRODUCTIONS: essa seção é usada para armazenar as classes dos componentes de interoperabilidade.

Por exemplo:

import bp
from bo import *
from bs import *

CLASSES = {
    'Python.RedditService': RedditService,
    'Python.FilterPostRoutingRule': bp.FilterPostRoutingRule,
    'Python.FileOperation': FileOperation,
    'Python.FileOperationWithIrisAdapter': FileOperationWithIrisAdapter,
}

PRODUCTIONS = [
    {
        'dc.Python.Production': {
        "@Name": "dc.Demo.Production",
        "@TestingEnabled": "true",
        "@LogGeneralTraceEvents": "false",
        "Description": "",
        "ActorPoolSize": "2",
        "Item": [
            {
                "@Name": "Python.FileOperation",
                "@Category": "",
                "@ClassName": "Python.FileOperation",
                "@PoolSize": "1",
                "@Enabled": "true",
                "@Foreground": "false",
                "@Comment": "",
                "@LogTraceEvents": "true",
                "@Schedule": "",
                "Setting": {
                    "@Target": "Host",
                    "@Name": "%settings",
                    "#text": "path=/tmp"
                }
            },
            {
                "@Name": "Python.RedditService",
                "@Category": "",
                "@ClassName": "Python.RedditService",
                "@PoolSize": "1",
                "@Enabled": "true",
                "@Foreground": "false",
                "@Comment": "",
                "@LogTraceEvents": "false",
                "@Schedule": "",
                "Setting": [
                    {
                        "@Target": "Host",
                        "@Name": "%settings",
                        "#text": "limit=10\nother<10"
                    }
                ]
            },
            {
                "@Name": "Python.FilterPostRoutingRule",
                "@Category": "",
                "@ClassName": "Python.FilterPostRoutingRule",
                "@PoolSize": "1",
                "@Enabled": "true",
                "@Foreground": "false",
                "@Comment": "",
                "@LogTraceEvents": "false",
                "@Schedule": ""
            }
        ]
    }
    }
]
7.12.4.1.1. Seção CLASSES

Essa seção é usada para armazenar as produções dos componentes de interoperabilidade.

Ela visa ajudar a registrar os componentes.

Esse dicionário tem a seguinte estrutura:

  • Chave: nome do componente
  • Valor:
    • Classe do componente (você precisa importar antes)
    • Módulo do componente (você precisa importar antes)
    • Outro dicionário com a seguinte estrutura:
      • module : nome do módulo do componente (opcional)
      • class : nome da classe do componente (opcional)
      • path : caminho do componente (obrigatório)

Por exemplo:

Quando o valor é uma classe ou módulo:

import bo
import bp
from bs import RedditService

CLASSES = {
    'Python.RedditService': RedditService,
    'Python.FilterPostRoutingRule': bp.FilterPostRoutingRule,
    'Python.FileOperation': bo,
}

Quando o valor é um dicionário:

CLASSES = {
    'Python.RedditService': {
        'module': 'bs',
        'class': 'RedditService',
        'path': '/irisdev/app/src/python/demo/'
    },
    'Python.Module': {
        'module': 'bp',
        'path': '/irisdev/app/src/python/demo/'
    },
    'Python.Package': {
        'path': '/irisdev/app/src/python/demo/'
    },
}
7.12.4.1.2. Seção de produções

Essa seção é usada para armazenar as produções dos componentes de interoperabilidade.

Ela visa ajudar a registrar uma produção.

Essa lista tem a seguinte estrutura:

  • Uma lista do dicionário com a seguinte estrutura:
    • dc.Python.Production: nome da produção
      • @Name: nome da produção
      • @TestingEnabled: enabled de teste da produção
      • @LogGeneralTraceEvents: eventos de rastreamento gerais do log da produção
      • Description: descrição da produção
      • ActorPoolSize: tamanho do pool de atores da produção
      • Item: lista dos itens da produção
        • @Name: nome do item
        • @Category: categoria do item
        • @ClassName: nome da classe do item
        • @PoolSize: tamanho do pool do item
        • @Enabled: enabled do item
        • @Foreground: foreground do item
        • @Comment: comentário do item
        • @LogTraceEvents: eventos de rastreamento do log do item
        • @Schedule: programação do item
        • Setting: lista de configurações do item
          • @Target: alvo da configuração
          • @Name: nome da configuração
          • #text: valor da configuração

A estrutura mínima de uma produção é:

PRODUCTIONS = [
        {
            'UnitTest.Production': {
                "Item": [
                    {
                        "@Name": "Python.FileOperation",
                        "@ClassName": "Python.FileOperation",
                    },
                    {
                        "@Name": "Python.EmailOperation",
                        "@ClassName": "UnitTest.Package.EmailOperation"
                    }
                ]
            }
        } 
    ]

Você também pode definir em @ClassName um item da seção CLASSES.

Por exemplo:

from bo import FileOperation
PRODUCTIONS = [
        {
            'UnitTest.Production': {
                "Item": [
                    {
                        "@Name": "Python.FileOperation",
                        "@ClassName": FileOperation,
                    }
                ]
            }
        } 
    ]

Como a produção é um dicionário, você pode adicionar no valor do dicionário de produção uma variável de ambiente.

Por exemplo:

import os

PRODUCTIONS = [
        {
            'UnitTest.Production': {
                "Item": [
                    {
                        "@Name": "Python.FileOperation",
                        "@ClassName": "Python.FileOperation",
                        "Setting": {
                            "@Target": "Host",
                            "@Name": "%settings",
                            "#text": os.environ['SETTINGS']
                        }
                    }
                ]
            }
        } 
    ]

7.13. Uso direto de Grongier.PEX

Se você não quiser usar o utilitário register_component, é possível adicionar um componente Grongier.PEX.BusinessService diretamente no portal de gerenciamento e configurar as propriedades:

  • %module:
    • Nome do módulo do seu código em python
  • %classname:
    • Nome da classe do seu componente
  • %classpaths:
    • Caminho onde está seu componente.
      • Pode ser um ou mais caminhos de classe (separados pelo caractere '|') necessários além de PYTHON_PATH

Por exemplo: component-config

8. Linha de comando

Desde a versão 2.3.1, você pode usar a linha de comando para registrar seus componentes e produções.

Para usá-la, você precisa utilizar o seguinte comando:

iop 

saída:

usage: python3 -m grongier.pex [-h] [-d DEFAULT] [-l] [-s START] [-k] [-S] [-r] [-M MIGRATE] [-e EXPORT] [-x] [-v] [-L]
optional arguments:
  -h, --help            display help and default production name
  -d DEFAULT, --default DEFAULT
                        set the default production
  -l, --lists           list productions
  -s START, --start START
                        start a production
  -k, --kill            kill a production (force stop)
  -S, --stop            stop a production
  -r, --restart         restart a production
  -M MIGRATE, --migrate MIGRATE
                        migrate production and classes with settings file
  -e EXPORT, --export EXPORT
                        export a production
  -x, --status          status a production
  -v, --version         display version
  -L, --log             display log

default production: PEX.Production

8.1. help

O comando help exibe a ajuda e o nome da produção padrão.

iop -h

saída:

usage: python3 -m grongier.pex [-h] [-d DEFAULT] [-l] [-s START] [-k] [-S] [-r] [-M MIGRATE] [-e EXPORT] [-x] [-v] [-L]
...
default production: PEX.Production

8.2. default

O comando default define a produção padrão.

Sem argumento, ele exibe a produção padrão.

iop -d

saída:

default production: PEX.Production

Com argumento, ele define a produção padrão.

iop -d PEX.Production

8.3. lists

O comando lists lista produções.

iop -l

saída:

{
    "PEX.Production": {
        "Status": "Stopped",
        "LastStartTime": "2023-05-31 11:13:51.000",
        "LastStopTime": "2023-05-31 11:13:54.153",
        "AutoStart": 0
    }
}

8.4. start

O comando start inicia uma produção.

Para sair do comando, pressione CTRL+C.

iop -s PEX.Production

saída:

2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting production
2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting item Python.FileOperation
2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting item Python.EmailOperation
...

8.5. kill

O comando kill encerra uma produção à força.

O comando kill é igual ao comando stop, mas força o encerramento.

O comando kill não aceita argumentos, porque só pode ser executada uma produção.

iop -k 

8.6. stop

O comando stop interrompe uma produção.

O comando stop não aceita argumentos, porque só pode ser executada uma produção.

iop -S 

8.7. restart

O comando restart reinicia uma produção.

O comando restart não aceita argumentos, porque só pode ser executada uma produção.

iop -r 

8.8. migrate

O comando migrate migra uma produção e classes com o arquivo de configurações.

O comando migate precisa receber o caminho absoluto do arquivo de configurações.

O arquivo de configurações precisa estar na mesma pasta que o código em python.

iop -M /tmp/settings.py

8.9. export

O comando export exporta uma produção.

Se nenhum argumento for fornecido, o comando export exporta a produção padrão.

iop -e

Se um argumento for fornecido, o comando export exporta a produção indicada no argumento.

iop -e PEX.Production

saída:

{
    "Production": {
        "@Name": "PEX.Production",
        "@TestingEnabled": "true",
        "@LogGeneralTraceEvents": "false",
        "Description": "",
        "ActorPoolSize": "2",
        "Item": [
            {
                "@Name": "Python.FileOperation",
                "@Category": "",
                "@ClassName": "Python.FileOperation",
                "@PoolSize": "1",
                "@Enabled": "true",
                "@Foreground": "false",
                "@Comment": "",
                "@LogTraceEvents": "true",
                "@Schedule": "",
                "Setting": [
                    {
                        "@Target": "Adapter",
                        "@Name": "Charset",
                        "#text": "utf-8"
                    },
                    {
                        "@Target": "Adapter",
                        "@Name": "FilePath",
                        "#text": "/irisdev/app/output/"
                    },
                    {
                        "@Target": "Host",
                        "@Name": "%settings",
                        "#text": "path=/irisdev/app/output/"
                    }
                ]
            }
        ]
    }
}

8.10. status

O comando status dá o status de uma produção.

O comando status não aceita argumentos, porque só pode ser executada uma produção.

iop -x 

saída:

{
    "Production": "PEX.Production",
    "Status": "stopped"
}

O status pode ser:

  • stopped (interrompido)
  • running (em execução)
  • suspended (suspenso)
  • troubled (com problema)

8.11. version

O comando version exibe a versão.

iop -v

saída:

2.3.0

8.12. log

O comando log exibe o log.

Para sair do comando, pressione CTRL+C.

iop -L

saída:

2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting production
2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting item Python.FileOperation
2021-08-30 15:13:51.000 [PEX.Production] INFO: Starting item Python.EmailOperation
...

9. Créditos

A maior parte do código foi retirada do PEX para Python, de Mo Cheng e Summer Gerry.

Funciona somente a partir do IRIS 2021.2

0
1 72
Artigo Danusa Calixto · Abr. 15, 2024 3m read

Visão geral

Muitas vezes enfrentamos problemas de conectividade com implantações do HealthShare (HS) no Microsoft Azure que possuem vários componentes do HealthShare (instâncias ou namespaces) instalados na mesma VM, principalmente quando precisamos nos comunicar com outros componentes do HS enquanto usamos o Azure Load Balancer (ILB) para fornecer a funcionalidade VIP de espelho.  Para detalhes sobre como e por que um balanceador de carga é usado com o espelhamento de banco de dados, confira este artigo da comunidade.

De acordo com a documentação do Azure Load Balancer, https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-overview#limitations, o comportamento padrão do Azure Internal Load Balancer é o seguinte:

...se um fluxo de saída de uma VM no pool de back-end tentar um fluxo para o front-end do Load Balancer interno no pool em que reside e for mapeado de volta para si mesmo, ambas as pernas do fluxo não corresponderão e o fluxo falhará.

Portanto, uma implantação do HealthShare com várias instâncias ou namespaces em uma determinada VM no pool de servidores do ILB que precisam se comunicar entre si falhará.  Por exemplo, aqui está um caso com a instância de espelho primário do Registro Unified Care Record (UCR) do HealthShare e a instância de espelho primário do HealthShare Patient Index, ambas na mesma VM do Azure.

   

No exemplo acima, o Registro UCR inicia uma conexão com 10.0.1.100 para que possa se comunicar com a instância do Patient Index. Há 50% de chance dessa conexão falhar, dependendo se os membros espelho primários de cada Patient Index e Registro UCR estão no mesmo host (10.0.1.10, nesse caso). 

Essa conexão falha porque o comportamento NAT padrão do ILB do Azure não executa o Source-NAT (SNAT) de entrada, e o IP de origem original é preservado. Os detalhes estão disponíveis no mesmo link da documentação da Microsoft acima:

Quando o fluxo é mapeado de volta para si mesmo, o fluxo de saída parece vir da VM para o front-end, e o fluxo de entrada correspondente parece vir da VM para si mesmo...  

Especificamente, o comportamento padrão do ILB do Azure é o seguinte:

  • O ILB do Azure não executa o Source-NAT de entrada e, portanto, o IP de origem original é preservado
  • Ao usar o conjunto de regras do balanceador de carga padrão para desabilitar o DSR (também conhecido como "IP flutuante"), ele executa o Destination-NAT (DNAT)

Isso resulta no seguinte (novamente, do link da documentação original acima):

Do ponto de vista do SO convidado, as partes de entrada e saída do mesmo fluxo não correspondem dentro da máquina virtual. A pilha TCP não reconhecerá essas metades do mesmo fluxo como parte do mesmo fluxo, já que a origem e o destino não correspondem.

Solução alternativa

Há várias opções disponíveis para solucionar esse problema do ILB do Azure, mas este artigo focará em apenas uma abordagem.

Adicionar um NIC secundário

São necessárias apenas duas etapas para fazer isso, da seguinte maneira:

  • Adicione um NIC secundário à VM com um endereço IP diferente (no diagrama a seguir, um NIC e endereço de .11 foram adicionados)
  • Configure o tráfego que força a rota estática (nível do SO) local destinado ao VIP do ILB (10.0.1.100) do NIC secundário

 

Isso permite que a comunicação seja bem-sucedida, agora que o back-end para o front-end tem endereços IP de origem (10.0.1.11) e destino diferentes (10.0.1.100 > DNAT > 10.0.1.10).

// exiba vários NIC
c:\pstools>ipconfig | findstr /i "ipv4"
   IPv4 Address. . . . . . . . . . . : 10.1.0.10
   IPv4 Address. . . . . . . . . . . : 10.1.0.11
 
// tráfego de rota estática destinado ao front-end do LB do NIC secundário
c:\pstools>route add 10.1.0.100 mask 255.255.255.255 10.1.0.1 if 18   ('if 18' indicates the interface to use for the outbound traffic)
 OK!

**Observação: a sintaxe do seu comando "route add" exato varia dependendo da sua rede exata e topologia de subnet.  Esse exemplo serve apenas para fins ilustrativos.  A documentação sobre o comando Route no Windows pode ser encontrada aqui e o Red Hat Enterprise Linux pode ser encontrado aqui.

0
0 86
Artigo Rochael Ribeiro · Abr. 12, 2024 1104m read

O Enterprise Monitor é um componente do Ensemble e pode ajudar as organizações a monitorar várias produções executadas em diferentes namespaces na mesma instância ou em namespaces executados em várias instâncias.

A documentação pode ser encontrada em:

http://docs.intersystems.com/ens20161/csp/docbook/DocBook.UI.Page.cls?KEY=EMONITOR_all#EMONITOR_enterprise

No Ensemble 2016.1, foram realizadas mudanças para esse utilitário funcionar com ambientes do HealthShare.

Este artigo mostrará o seguinte:

  • Como configurar o Enterprise Monitor para sites do HealthShare
  • Alguns recursos do Enterprise Monitor
  • Alguns recursos do Enterprise Message Viewer

Para este artigo, usei a seguinte versão do HealthShare:

Cache para Windows (x86-64) 2016.1 (Build 656U) Sex 11 Mar 2016 17:42:42 EST [Módulos do HealthShare:Core:14.02.2415 + Linkage Engine:14.02.2415 + Patient Index:14.02.2415 + Clinical Viewer:14.02.2415 + Active Analytics:14.02.2415] __

Configurar o Enterprise Monitor

Criar um novo namespace

O Enterprise Monitor é executado no seu próprio namespace e pode estar localizado em uma instância existente ou separada.  Neste artigo, ele será executado na mesma instância.

Para criar um namespace:

  • Acesse o Portal de Gerenciamento de Sistemas -> System Administration (Administração do sistema) -> Configuration (Configuração) -> System Configuration (Configuração do sistema) -> Namespaces
  • Clique no botão "Create New Namespace" (Criar novo namespace)

Neste exemplo, criei um namespace HSMONITOR.  Também criei um banco de dados chamado HSMONITOR

Captura de tela de como criar um namespace:

Editar o aplicativo da Web

Para instâncias do HealthShare, o aplicativo da Web define, por padrão, o "Session Cookie Path" (Caminho do cookie da sessão) como "/csp/healthshare/".   Se o namespace do Enterprise Monitor estiver em uma instância com outros namespaces do HealthShare, mude o "Session Cookie Path" do namespace do Enterprise Monitor para "/csp/healthshare/[namespace]/".

Para mudar o aplicativo da Web:

  • Acesse o Portal de Gerenciamento de Sistema -> System Administration -> Security (Segurança) -> Applications (Aplicativos) -> Web Applications (Aplicativos da Web)
  • Selecione o aplicativo da Web que foi criado para seu namespace do Enterprise Monitor. No meu caso, é "/csp/healthshare/hsmonitor".
  • Selecione o menu suspenso de "Session Cookie Path" e altere para "/csp/healthshare/[namespace]/". No meu caso, selecionei "/csp/healthshare/hsmonitor/".

Captura de tela de como alterar o aplicativo da Web:

Adicionar uma credencial

O Enterprise Monitor usa serviços da Web para se comunicar com diversos sistemas, então ele precisa de um nome de usuário/senha para validar a comunicação. O Ensemble consegue fazer isso usando credenciais. Todos os namespaces do HealthShare usam credenciais com o nome de usuário "HS_Services"

Vamos adicionar "HS_Services" às credenciais do namespace do Ensemble que criamos para o Enterprise Monitor.

Etapas para criar uma credencial:

  • Acesse o Portal de Gerenciamento de Sistemas ->  Ensemble
  • Selecione o namespace do Enterprise Monitor, se solicitado, ou mude o namespace usando o link "switch" (trocar) no topo do Portal de Gerenciamento de Sistemas.
  • Acesse Configure (Configurar) -> Credentials (Credenciais)
  • Clique no botão "New" (Novas)
  • Defina o ID como "HS_Services"
  • Defina "UserName" (Nome de usuário) como "HS_Services"
  • Defina "Password" como a senha que o "HS_Services" usa para os outros namespaces do HealthShare.

Captura de tela de como adicionar credenciais:

Criar uma produção

Em seguida, criamos uma produção que usa o serviço empresarial "Ens.Enterprise.MonitorService".  Essa é a produção que será executada no namespace do Enterprise Monitor que configuramos.

Confira a seguir a produção que criei.  Observe que ela estende "Ens.Enterprise.Production" e inclui um item de serviço empresarial, que foi adicionado (Ens.Enterprise.MonitorService).

Class HSMONITOR.MonitorProduction Extends Ens.Enterprise.Production
{
XData ProductionDefinition
{
&lt;Production Name="HSMONITOR.MonitorProduction">
    &lt;ActorPoolSize>2&lt;/ActorPoolSize>
    &lt;Item Name="Ens.Enterprise.MonitorService" ClassName="Ens.Enterprise.MonitorService" PoolSize="1" />
&lt;/Production>
}

}

Depois disso, você pode iniciar a produção no namespace do Enterprise Monitor que você criou.  Nesse exemplo, iniciei o HSMONITOR.MonitorProduction no meu namespace HSMONITOR.

Adicionar um sistema empresarial

Agora que a produção está sendo executada, podemos adicionar os sistemas empresariais que queremos monitorar.

Para criar um novo sistema empresarial:

  • Acesse o Portal de Gerenciamento de Sistemas -> Ensemble
  • Confira se você está no namespace do Enterprise Monitor
  • Acesse Configure -> Enterprise Systems (Sistemas empresariais)
  • Clique no novo botão "New Connection" (Nova conexão)

Captura de tela dos sistemas empresariais:

Para adicionar uma nova conexão:

  • Insira o nome
  • Insira o endereço IP da Web
  • Insira o namespace
  • Insira o caminho para o serviço de aplicativo da Web
  • Insira as credenciais Soap
  • Clique no botão "Save" (Salvar).

Captura de tela de como adicionar uma conexão a HSREGISTRY:

Você pode adicionar vários sistemas empresariais para refletir seus ambientes do HealthShare.  É possível adicionar gateways de borda, gateways de acesso, outros componentes do HealthShare, como Personal Community, Patient Index, Health Insight, etc.

A maioria das informações do HealthShare está localizada no registro de serviços.

Coloquei meu namespace do Enterprise Monitor na mesma instância que o HSREGISTRY.

Escrevi e executei o seguinte código no meu namespace HSMONITOR para criar sistemas empresariais de forma automática com base nas informações localizadas no registro de serviços.

Código de amostra:

ClassMethod BuildEM()
{
                set tSaveNamespace = $namespace
                zn "HSREGISTRY"             
           
                set sql="select EndPoint,Name,Info from HS_Registry_Service.SOAP"
                set statement = ##class(%SQL.Statement).%New()
                set tSC = statement.%Prepare(sql)
                quit:$$$ISERR(tSC)
                set result = statement.%Execute()
                while result.%Next() {
                                set tEndPoint = result.EndPoint
                                set tName = result.Name
                                set tInfo = result.Info
                                If tName = "HSREGISTRY" set tName = ":"_tName
                                If tName = "HSPI" set tName = ":"_tName
                                If $p(tName,":",2) = "WebServices" set tName = ":"_tName
                                If tName = "HSCommunity.PIXv3.Consumer" set tName = ":HSCOMMUNITY"
                                Continue:$p(tName,":",2)=""
                                set tMCName = $p(tName,":",2)
                                set tMCNamespace = $p(tEndPoint,"/",6)
                                set tMCWebIP = tInfo
                                set tMCHomePath = "/"_$p(tEndPoint,"/",4,6)_"/"
                                set tMCServicePath = "/"_$p(tEndPoint,"/",4,7)_"/"
                                set aMC(tMCName)=$lb(tMCNamespace,tMCWebIP,tMCHomePath,tMCServicePath)
                }
                zn tSaveNamespace
                ///Now we have an array of namespaces, create Monitor entries
                set tName = ""
                do {
                  set tName=$O(aMC(tName))
                  if tName '="" {
                                set tMonitorClient = ##class(Ens.Enterprise.MonitorClient).%New()
                                set tMonitorClient.Name=tName 
                                set tMonitorClient.WebIPAddress=$list(aMC(tName),2) ;IP/Port
                                set tMonitorClient.Namespace=$list(aMC(tName),1) ;NameSpace
                                set tMonitorClient.HomePage="%25CSP.Portal.Home.zen"
                                set tMonitorClient.HomePath=$list(aMC(tName),3) ;"/csp/healthshare/[namespace]/"
                                set tMonitorClient.QueueThreshold=""
                                set tMonitorClient.ServicePath=$list(aMC(tName),4) ;"/csp/healthshare/[namespace]/services/"
                                set tMonitorClient.SOAPCredentials="HS_Services"
                                set tMonitorClient.SSLCheckServerIdentity="1"
                                set tMonitorClient.SSLConfig=""
                                set tMonitorClient.Version="2016.1.1.108.1."
                                set tSC=tMonitorClient.%Save()
                                w !,tName,": ",$system.Status.DisplayError(tSC)
                  }
                } while tName '= ""
                quit
}

Enterprise Monitor

Agora que temos entradas no sistema empresarial, você verá uma nova opção de menu no namespace do Enterprise Monitor do Ensemble.  Essa nova opção de menu será "Enterprise Monitor".

Captura de tela da nova opção de menu:

Ao selecionar "Enterprise Monitor", vemos o seguinte:

Agora podemos ver em um único local quais produções do HealthShare estão "Running" (em execução) ou "Stopped" (interrompidas), com links para as configurações das que estiverem em execução.

Ao selecionar uma linha, é possível ver os detalhes de cada ambiente.  Confira este exemplo:

Essa tela mostra detalhes sobre:

  • Conexões de entrada
  • Conexões de saída
  • Filas
  • Registro de eventos
  • Gráfico de atividades
  • Lista de mensagens do Ensemble

Você também pode adicionar métricas personalizadas.

Confira mais informações sobre o monitor de produções:

http://docs.intersystems.com/ens20161/csp/docbook/DocBook.UI.Page.cls?KEY=EMONITOR_production

Enterprise Message Viewer

Com o Enterprise Monitor configurado, você também pode conferir o Enterprise Message Viewer.

Neste exemplo, acesse "Patient Search" (Pesquisa de pacientes) no HSACCESS, faça uma consulta, selecione um paciente e veja as informações mostradas no Clinical Viewer.

Ao acessar o Enterprise Message Viewer, é possível ver todos os sistemas chamados e as informações que foram usadas para realizar essa ação do Clinical Viewer.

Agora há um único lugar para ver como as mensagens estão fluindo em todos os sistemas/namespaces no ambiente do HealthShare.

OBSERVAÇÃO:  esse utilitário Enterprise Message Viewer contém somente informações básicas do cabeçalho de mensagens do Ensemble.  Ele fornece links para os detalhes específicos da sessão e direciona você aos detalhes e rastreamentos da mensagem do Ensemble.

Conclusão

O Enterprise Monitor e o Enterprise Message Viewer são ferramentas novas no Ensemble que ajudarão os clientes do HealthShare a gerenciar os ambientes e ver fluxos de trabalho no HealthShare.

Enterprise Monitor:

  • Local único para ver quais ambientes estão em execução e quais foram interrompidos
  • Links para todas as configurações de produção no ambiente do HealthShare
  • Consulta dos detalhes de cada produção, incluindo
    • Conexões de entrada
    • Conexões de saída
    • Filas
    • Registro de eventos
    • Gráfico de atividades
    • Mensagens

Enterprise Message Viewer:

  • Visualização única de todas as mensagens no ambiente do HealthShare
0
0 53
Artigo Danusa Calixto · Abr. 12, 2024 4m read
       

Como incluir dados do IRIS no seu Data Warehouse do Google Big Query e em suas explorações de dados do Data Studio.  Neste artigo, vamos usar o Google Cloud Dataflow para nos conectarmos com o InterSystems Cloud SQL Service  e criar um job para persistir os resultados de uma consulta do IRIS no Big Query em um intervalo. 

Se você teve a sorte de ganhar acesso ao Cloud SQL no Global Summit 2022, conforme mencionado em "InterSystems IRIS: What's New, What's Next", o exemplo será muito fácil. No entanto, também é possível fazer isso com qualquer listener acessível publicamente ou por VPC que você provisionar.

Pré-requisitos

 
Provisione o InterSystems Cloud SQL para uso temporário
Talvez você precise fazer algumas ligações ou solicitar acesso pelo portal, como fiz para testar o InterSystems Cloud SQL, mas é uma maneira muito rápida de começar a trabalhar em segundos para realizar essa demonstração ou suas cargas de trabalho do IRIS.

Ao inspecionar sua implantação, você pode acessar o painel "Conexões externas" na guia de visão geral, criar um URL de conexão e manter suas credenciais.  Fomos diretamente para o acesso público (0.0.0.0/0) ao listener e escolhemos não critografá-lo.
 
Do acima, você divulgará as seguintes informações...
ConnectionURL: 

jdbc:IRIS://k8s-c5ce7068-a4244044-265532e16d-2be47d3d6962f6cc.elb.us-east-1.amazonaws.com:1972/USER
User/Pass:
SQLAdmin/Testing12!
DriverClassName:
com.intersystems.jdbc.IRISDriver
 
Configure o Google Cloud Platform
  • Provisione um projeto do GCP
gcloud projects create iris-2-datastudio --set-as-default
  • Ative o Big Query
  • Ative o DataFlow
  • Enable Cloud Storage
gcloud services enable  bigquery.googleapis.com
gcloud services enable dataflow.googleapis.com
gcloud services enable storage.googleapis.com
  • Crie um bucket do Cloud Storage
gsutil mb gs://iris-2-datastudio
wget https://github.com/intersystems-community/iris-driver-distribution/raw/main/intersystems-jdbc-3.3.0.jar
gsutil cp intersystems-jdbc-3.3.0.jar gs://iris-2-datastudio
  • Crie um conjunto de dados do Big Query
bq --location=us mk \
--dataset \
--description "sqlaas to big query" \
iris-2-datastudio:irisdata
  • Crie uma tabela de destino do Big Query

Aqui, uma vantagem superpoderosa se torna meio incômoda para nós.  O Big Query pode criar tabelas dinamicamente se você fornecer um esquema com sua carga útil. Isso é ótimo dentro de pipelines e soluções, mas, em nosso caso, precisamos estabelecer a tabela com antecedência.  O processo é simples, já que você pode exportar um CSV do banco de dados do IRIS facilmente com algo como o DBeaver, depois invocar a caixa de diálogo "criar tabela" abaixo do conjunto de dados criado e usar o CSV para criar sua tabela.  Verifique se "gerar esquema automaticamente" está marcado na parte inferior da caixa de diálogo.
 Isso conclui a configuração do Google Cloud Platform, e deve estar tudo pronto para configurar e executar o job do Dataflow.

Job do Google Dataflow
Se você seguiu as etapas acima, deverá ter o seguinte no seu inventário para executar o job de ler os dados do InterSystems IRIS e ingeri-los no Google Big Query usando o Google Dataflow.
No Console do Google Cloud, acesse o Dataflow e selecione "Criar job a partir do modelo"
 
Essa é uma ilustração um tanto desnecessária/exaustiva sobre como preencher um formulário com os pré-requisitos gerados, mas indica a origem dos componentes...

 

 ... para completar, abra a seção inferior e forneça suas credenciais do IRIS.

 

Para quem achou essas capturas de tela ofensivas à própria inteligência, aqui está o caminho alternativo para deixar você dentro da sua zona de conforto na CLI para executar o job​:

gcloud dataflow jobs run iris-2-bq-dataflow \
--gcs-location gs://dataflow-templates-us-central1/latest/Jdbc_to_BigQuery \
--region us-central1 --num-workers 2 \
--staging-location gs://iris-2-datastudio/tmp \
--parameters connectionURL=jdbc:IRIS://k8s-c5ce7068-a4244044-265532e16d-2be47d3d6962f6cc.elb.us-east-1.amazonaws.com:1972/USER,driverClassName=com.intersystems.jdbc.IRISDriver,query=SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE, SELF_REFERENCING_COLUMN_NAME, REFERENCE_GENERATION, USER_DEFINED_TYPE_CATALOG, USER_DEFINED_TYPE_SCHEMA, USER_DEFINED_TYPE_NAME, IS_INSERTABLE_INTO, IS_TYPED, CLASSNAME, DESCRIPTION, OWNER, IS_SHARDED FROM INFORMATION_SCHEMA.TABLES;,outputTable=iris-2-datastudio:irisdata.dataflowtable,driverJars=gs://iris-2-datastudio/intersystems-jdbc-3.3.0.jar,bigQueryLoadingTemporaryDirectory=gs://iris-2-datastudio/input,username=SQLAdmin,password=Testing12!

Após iniciar o job, aproveite a glória de uma execução de job bem-sucedida:

 
Resultados
Observando a consulta e os dados de origem no InterSystems Cloud SQL...
 

... e inspecionando os resultados no Big Query, parece que realmente temos os dados do InterSystems IRIS no Big Query.

 
Depois de ter os dados no Big Query, é simples incluir nossos dados do IRIS no Data Studio ao selecionar o Big Query como fonte de dados... o exemplo abaixo não é muito elegante, mas você pode ver rapidamente os dados do IRIS prontos para manipulação no seu projeto do Data Studio.


 
 

0
0 93
Artigo Danusa Calixto · Abr. 8, 2024 6m read

image

Este artigo abordará a transferência do controle do provisionamento do InterSystems Kubernetes Operator e o início da sua jornada com a gestão da sua própria "nuvem" de soluções InterSystems através de práticas Git Ops. Esse padrão de implantação também é o caminho de execução para o PID^TOO||| Motor de Resolução de Identidade de Respiração FHIR.

Git Ops

Recomendo que você faça sua própria pesquisa ou pergunte ao seu LLM favorito sobre o Git Ops, mas posso parafrasear aqui como o entendemos. Git Ops é um paradigma de implantação alternativo, onde o próprio Cluster Kubernetes "extrai" atualizações de manifestos que residem no controle de origem para gerenciar o estado das suas soluções, tornando o "Git" uma parte essencial do nome.

Pré-requisitos

  • Provisionar um Cluster Kubernetes, isso foi testado em clusters EKS, GKE e MicroK8s
  • Provisionar um GitLab, GitHub ou outro repositório Git que possa ser acessado pelo seu Cluster Kubernetes

Argo CD

A estrela do show aqui é o ArgoCD, que fornece uma abordagem declarativa de entrega contínua com uma IU extremamente bem feita. Usar o gráfico no seu cluster é muito fácil, exigindo apenas alguns toques.

kubectl create namespace argocd
kubectl apply -n argocd -f \
https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Vamos fazer login na IU do ArgoCD no seu Cluster Kubernetes. Para isso, você precisa obter o segredo que foi criado para a IU e configurar um encaminhamento de porta para torná-lo acessível no seu sistema.

Obtenha o segredo
Descriptografe e coloque-o na área de transferência. image

Encaminhamento de porta
Redirecione a porta 4000 (ou qualquer outra) para seu host local

image

IU
Acesse https://0.0.0.0:4000, forneça o segredo na tela de login e faça login.

image

InterSystems Kubernetes Operator (IKO)

As instruções para obter o gráfico IKO Helm estão na própria documentação. Depois de obtê-las, confira no seu repositório git em uma ramificação de recurso. Eu forneceria um repositório de amostra, mas infelizmente não posso fazer isso sem uma violação da redistribuição, porque o gráfico não parece estar disponível em um repositório público.

Crie você mesmo uma ramificação de recurso no seu repositório git e descompacte o gráfico IKO Helm em um único diretório. Conforme abaixo, é o iko/iris_operator_amd-3.5.48.100 fora da raiz do repositório.

Na ramificação feature/iko como exemplo:

├── iko
│   ├── AIKO.pdf
│   └── iris_operator_amd-3.5.48.100
│       ├── chart
│       │   └── iris-operator
│       │       ├── Chart.yaml
│       │       ├── templates
│       │       │   ├── apiregistration.yaml
│       │       │   ├── appcatalog-user-roles.yaml
│       │       │   ├── cleaner.yaml
│       │       │   ├── cluster-role-binding.yaml
│       │       │   ├── cluster-role.yaml
│       │       │   ├── deployment.yaml
│       │       │   ├── _helpers.tpl
│       │       │   ├── mutating-webhook.yaml
│       │       │   ├── service-account.yaml
│       │       │   ├── service.yaml
│       │       │   ├── user-roles.yaml
│       │       │   └── validating-webhook.yaml
│       │       └── values.yaml

Configuração do IKO
Crie o namespace isc e adicione o segredo para containers.intersystems.com nele.

kubectl create ns isc

kubectl create secret docker-registry \
pidtoo-pull-secret --namespace isc \
--docker-server=https://containers.intersystems.com \
--docker-username='ron@pidtoo.com' \
--docker-password='12345'

Isso deve concluir a configuração do IKO e permitir que ele seja delegado inteiramente por Git Ops para o Argo CD.

Conecte o Git ao Argo CD

Essa é uma etapa simples na UI do Argo CD para conectar o repositório. Essa etapa APENAS "conecta" o repositório, a configuração adicional estará no próprio repositório.

image

Declare a ramificação ao Argo CD

Configure o Kubernetes para sondar a ramificação pelo values.yml do Argo CD no gráfico do Argo CD. A maioria desses locais no repositório git fica por sua conta, mas a maneira teimosa de declarar as coisas no seu repositório pode estar em um paradigma "App de Apps".

Considere criar a estrutura de pastas abaixo e os arquivos que precisam ser criados como um índice a seguir:

├── argocd
│   ├── app-of-apps
│   │   ├── charts
│   │   │   └── iris-cluster-collection
│   │   │       ├── Chart.yaml  ## Chart
│   │   │       ├── templates
│   │   │       │   ├── iris-operator-application.yaml  ## IKO As Application
│   │   │       └── values.yaml ## Application Chart Values
│   │   └── cluster-seeds
│   │       ├── seed.yaml  ## Cluster Seed

Gráfico

apiVersion: v1
description: 'pidtoo IRIS cluster'
name: iris-cluster-collection
version: 1.0.0
appVersion: 3.5.48.100
maintainers:
  - name: intersystems
    email: support@intersystems.com  

IKO como aplicativo

apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: iko
      namespace: argocd
    spec:
      destination:
        namespace: isc
        server: https://kubernetes.default.svc
      project: default
      source:
        path: iko/iris_operator_amd-3.5.48.100/chart/iris-operator
        repoURL: {{ .Values.repoURL }}
        targetRevision: {{ .Values.targetRevision }}
      syncPolicy:
        automated: {}
        syncOptions:
        - CreateNamespace=true  

Valores de gráfico do aplicativo IKO

targetRevision: main
repoURL: https://github.com/pidtoo/gitops_iko.git

Semente do cluster

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: gitops-iko-seed
  namespace: argocd
  labels:
    isAppOfApps: 'true'
spec:
  destination:
    namespace: isc
    server: https://kubernetes.default.svc
  project: default
  source:
    path: argocd/app-of-apps/charts/iris-cluster-collection
    repoURL: https://github.com/pidtoo/gitops_iko.git
    targetRevision: main
  syncPolicy:
    automated: {}
    syncOptions:
    - CreateNamespace=true

Semeie o cluster!

Essa é a última palavra sobre a interação com seus aplicativos Argo CD/IKO Cluster, o resto fica por conta do Git!

kubectl apply -n argocd -f argocd/app-of-apps/cluster-seeds/seed.yaml

Mesclar com o principal

Ok, é aqui que vemos como fomos na IU. Você deve começar imediatamente a ver no Argo CD os aplicativos começando a ganhar vida.

A visão dos apps:
image

Visão do InterSystems Kubernetes Operator
imageimage

Bem-vindo ao GitOps com o InterSystems Kubernetes Operator!

As demonstrações do Git são as melhores! - Live de 19 de outubro de 2023

Ron Sweeney, Arquiteto Principal, Integration Required, LLC (PID^TOO) Dan McCracken, COO, Devsoperative, INC

0
0 104
Artigo Danusa Calixto · Abr. 5, 2024 6m read

Neste artigo, vou abordar o teste e a depuração dos aplicativos da Web Caché (principalmente REST) com ferramentas externas. A segunda parte abrange ferramentas de Caché.

Você escreveu um código do servidor e quer testar em um cliente ou já tem um aplicativo da Web e ele não funciona. É aqui que entra a depuração. Neste artigo, vou mostrar desde as ferramentas mais fáceis de usar (navegador) até as mais completas (analisador de pacotes). Porém, primeiro, vamos falar um pouco sobre os erros mais comuns e como eles podem ser resolvidos.

Erros

401 Não Autorizado

Acho que é o erro encontrado com mais frequência ao implantar para a produção. O servidor de desenvolvimento local geralmente tem uma configuração de segurança mínima ou normal, mas convencional. No entanto, o servidor de produção pode ter um esquema mais restritivo. Portanto:

  • Confira se você fez login
  • Confira se o usuário tem acesso ao banco de dados/tabela/procedimento/linha/coluna que você quer acessar
  • Confira se a solicitação OPTIONS pode ser realizada por um usuário não autorizado

404 Não Encontrado

Confira:

  • Se o url está correto
  • Caso seja um aplicativo novo e você esteja usando um servidor da Web externo, recarregar o servidor da Web pode ajudar

Erros do aplicativo

De certa forma, é o mais fácil de encontrar — o stack trace ajuda. A resolução é completamente específica ao aplicativo.

Ferramentas de depuração

Navegador da Web

A principal ferramenta de depuração sempre disponível é o navegador da Web, de preferência o Chrome, mas o Firefox também é suficiente. As solicitações GET podem ser testadas ao inserir o URL na barra de endereço, todas as outras solicitações exigem um aplicativo da Web ou a escrita de código js. A abordagem geral é:

  • Pressione F12 para abrir as ferramentas de desenvolvedor.
  • Acesse a guia Network (Rede).
  • Marque a caixa de seleção "Preserve Log" (Preservar registro), se não estiver selecionada.
  • Exiba apenas solicitações XHR.
  • Realize a ação com problemas no aplicativo da Web.

Depois, você pode examinar as solicitações e reenviá-las. O Firefox também pode editar as solicitações antes de repeti-las.

Vantagens:

  • Sempre disponível
  • Fácil de usar (os usuários finais podem enviar capturas de tela das guias Network e Console)
  • É um ambiente de usuário final

Desvantagens:

  • Não mostra respostas parcialmente enviadas/corrompidas/etc.
  • Lento para respostas grandes
  • Lento para um número grande de respostas
  • Tudo é feito manualmente

Cliente REST

O cliente REST é um aplicativo da Web independente ou um complemento do navegador da Web criado especificamente para testar aplicativos da Web. Eu uso Postman, mas há muitos outros. Veja como é a depuração no Postman:

O Postman trabalha com solicitações agrupadas em coleções. A solicitação pode ser enviada no ambiente. O ambiente é uma coleção de variáveis. Por exemplo, no meu ambiente CACHE@localhost, a variável do host está definida como localhost e o usuário como _SYSTEM. Quando a solicitação é enviada, as variáveis são substituídas pelos seus valores para o ambiente escolhido e a solicitação é enviada.

Confira um exemplo de coleção e ambiente para o projeto MDX2JSON.

Vantagens:

  • Escreva uma única vez e use em todos os lugares
  • Melhor controle sobre a solicitação
  • Embelezamento das respostas

Desvantagens:

  • <s>A depuração de solicitações em cadeia (a resposta à request1 pode forçar a request2 ou request 2B) ainda é manual</s> (Atualização de 22 de fevereiro: possível no Postman)
  • Às vezes, falha com respostas parcialmente enviadas/corrompidas/etc.

Proxy de depuração HTTP

Um aplicativo independente que registra tráfego HTTP(S). As solicitações registradas podem ser modificadas e reenviadas. Eu uso Charles e Fiddler.

Vantagens:

  • Processa respostas parcialmente enviadas/corrompidas/etc.
  • Embelezamento das respostas
  • Melhor suporte para tráfego HTTPS (do que no analisador de pacotes)
  • Consegue capturar sessões

Desvantagens:

  • Algo (aplicativo da Web/cliente REST/código JS) é necessário para enviar a solicitação

Analisador de pacotes

Um programa de computador consegue interceptar e registrar o tráfego transmitido por uma rede. Com os fluxos de dados fluindo em toda a rede, o sniffer captura cada pacote e, se necessário, decodifica os dados brutos do pacote. Essa é a opção mais completa, mas também exige um pouco de habilidade para a operação adequada. Eu uso o WireShark. Veja um breve guia sobre a instalação e o uso:

  1. Se você quiser capturar pacotes locais, leia sobre o loopback e instale o software de pré-requisito (npcap para windows)
  2. Instale o WireShark
  3. Configure filtros de captura (por exemplo, um filtro para só capturar tráfego na porta 57772: port 57772
  4. Inicie a captura
  5. Configure filtros de exibição (por exemplo, um filtro para só exibir tráfego http para um ip específico: ip.addr == 1.2.3.4 && http

Confira um exemplo de captura de tráfego http (filtro de exibição) na porta 57772 (filtro de captura):

 Vantagens:

  • Processa respostas parcialmente enviadas/corrompidas/etc.
  • Consegue capturar uma grande quantidade de tráfego
  • Consegue capturar qualquer coisa
  • Consegue capturar sessões

Desvantagens:

  • Algo (aplicativo da Web/cliente REST/código JS) é necessário para enviar a solicitação

O que usar

Bem, isso depende da finalidade. Primeiro, podemos ter como objetivo registrar (proxy de depuração, analisador de pacotes) ou gerar (navegador, cliente REST) solicitações.

Se você estiver desenvolvendo uma API Web REST, o cliente REST é a maneira mais rápida de testar o funcionamento.

No entanto, se as solicitações do cliente REST funcionarem, mas o aplicativo da Web cliente não, talvez seja necessário o proxy de depuração http e o analisador de pacotes.

Se você tiver clientes e precisar desenvolver uma API do lado do servidor para trabalhar com eles, precisará do proxy de depuração http ou do analisador de pacotes.

É melhor estar familiarizado com todos os 4 tipos de ferramentas e mudar rapidamente entre eles se o atual não der conta do trabalho.

Às vezes, a ferramenta ideal é óbvia.

Por exemplo, recentemente, desenvolvi uma API do lado do servidor para um protocolo de extensão http popular. Os requisitos eram:

  • Os clientes já estavam escritos e o código não podia ser alterado
  • Clientes diferentes têm comportamentos diferentes
  • O comportamento no http e https varia
  • O comportamento com diferentes tipos de autenticação varia
  • Até cem solicitações por segundo para cada cliente
  • Todos ignoram o RFC

Há só uma solução aqui: o analisador de pacotes.

Ou, se estou desenvolvendo uma API REST para consumo de JS, o cliente REST é uma ferramenta perfeita para testes.

Ao depurar o aplicativo da Web, comece com o navegador.

Na Parte 2, vamos discutir o que pode ser feito (muita coisa) para a depuração da Web no lado do Caché.

Quais são suas abordagens para depurar a comunicação no lado do cliente?

0
0 94
Artigo Danusa Calixto · Abr. 4, 2024 3m read

Olá, Desenvolvedores!

Suponha que você tenha uma classe persistente com dados e queira ter uma IU Angular simples para visualizar os dados e fazer operações CRUD.

Recentemente, @Alberto Fuentes descreveu como desenvolver uma IU Angular para seu aplicativo do InterSystems IRIS usando RESTForms2. 

Neste artigo, quero explicar a você como obter uma IU Angular simples para fazer operações CRUD e visualizar seus dados de classes do InterSystems IRIS automaticamente em menos de 5 minutos.

Vamos lá!

Para isso, você precisará do seguinte:

Usarei uma classe Data.Countries, que gerei e importei pelo csvgen usando este comando:

d ##class(community.csvgen).GenerateFromURL("https://raw.githubusercontent.com/datasciencedojo/datasets/master/WorldDBTables/CountryTable.csv",",","Data.Countries"

Para criar uma IU Angular, precisamos expor a API REST para essa classe, que servirá as operações CRUD.

Vamos usar o módulo restforms2 para isso. 

Esse comando no dockerfile instala restforms2 no contêiner IRIS:

zpm "install restforms2" \

Para adicionar uma API REST, precisamos derivar a classe de Form.Adaptor:

Class Data.Countries Extends (%Library.Persistent, Form.Adaptor)

Adicione os parâmetros restforms2 à classe persistente para gerenciar o comportamento geral: parâmetro de classificação, nome de exibição etc.:

// Nome do formulário, e não uma chave global, então pode ser qualquer coisa
Parameter FORMNAME = "Countries";

/// Permissões padrão /// Objetos desse formulário podem ser Criados, Lidos, Atualizados e Excluídos /// Redefina esse parâmetro para mudar as permissões para todo mundo /// Redefina o método checkPermission (veja Form.Security) para essa classe  /// para adicionar a segurança personalizada com base em usuário/funções/etc. Parameter OBJPERMISSIONS As %String = "CRUD";

/// Propriedade usada para informações básicas sobre o objeto /// Por padrão, o método getObjectDisplayName recebe seu valor dela Parameter DISPLAYPROPERTY As %String = "name";

Perfeito. Em seguida, podemos usar a sintaxe restforms2 para informar ao restforms2 quais propriedades queremos expor às operações CRUD. Você pode fazer isso adicionando o atributo "DISPLAYNAME =" às propriedades que você quer expor em restforms2-ui. Exemplo:

Property code As %Library.String(MAXLEN = 250) [ SqlColumnNumber = 2 ];

Property name As %Library.String(DISPLAYNAME = "Name", MAXLEN = 250) [ SqlColumnNumber = 3 ];

Property continent As %Library.String(DISPLAYNAME = "Continent", MAXLEN = 250) [ SqlColumnNumber = 4 ];

Property region As %Library.String(DISPLAYNAME = "Region", MAXLEN = 250) [ SqlColumnNumber = 5 ];

Property surfacearea As %Library.Integer(DISPLAYNAME = "Surface Area", MAXVAL = 2147483647, MINVAL = -2147483648) [ SqlColumnNumber = 6, SqlFieldName = surface_area ];

Property independenceyear As %Library.Integer(DISPLAYNAME = "Independence Year", MAXVAL = 2147483647, MINVAL = -2147483648) [ SqlColumnNumber = 7, SqlFieldName = independence_year ];

Ótimo! Agora vamos introduzir a camada de UI.  Esse comando no dockerfile instala restforms2-ui, que é a IU Angular para Restform2:

zpm "install restforms2-ui" \

É isso! Vamos examinar a IU para sua classe, que você pode encontrar no URL server:port/restforms2-ui:

RESTForms são usados com as classes de teste Person e Company, e você pode usar isso para examinar os recursos de restformsUI. No momento, é possível editar campos de string, número, booleano, data e consulta.

Você pode testar tudo isso no seu laptop, se clonar e compilar este repositório:

docker-compose up -d --build

E abrir o URL:

localhost:port/restforms2-ui/index.html

ou, se você usar o VSCode, selecione esse item do menu:

Boa programação e fique ligado!

0
0 87
Artigo Danusa Calixto · Abr. 4, 2024 12m read

Olá, Desenvolvedores!

Hoje quero falar sobre um assunto que já me deu trabalho. Tenho certeza de que isso deve ter acontecido com muitos de vocês (o chamado "gargalo"). Como esse é um tema amplo, este artigo focará apenas em identificar solicitações HTTP recebidas que podem estar causando problemas de lentidão. Também disponibilizarei uma pequena ferramenta que desenvolvi para ajudar a identificá-las.

Nosso software está cada vez mais complexo, processando um grande número de solicitações de diferentes origens, seja aplicativos de front-end ou back-end de terceiros. Para garantir um desempenho ideal, é fundamental ter um sistema de registro capaz de obter algumas medições importantes, como tempo de resposta, número de referências globais e número de linhas de código executadas para cada resposta HTTP. Como parte do meu trabalho, participo do desenvolvimento de software EMR e da análise de incidentes.  Como a carga do usuário vem principalmente de solicitações HTTP (API REST ou aplicativo CSP), a necessidade desse tipo de medição quando ocorrem problemas generalizados de lentidão se tornou óbvia.

Medição de tempo de resposta

Um dos elementos mais relevantes para avaliar o desempenho de um aplicativo é o tempo de resposta. Cada solicitação precisa ser respondida dentro de um prazo razoável para fornecer uma experiência satisfatória ao usuário. Por isso que, ao registrar o tempo de resposta de cada solicitação, um sistema de registro ajuda a identificar o desempenho ruim. Também podemos usar essas informações para identificar quais APIs ou CSPs são mais lentos a fim de otimizá-los e aumentar a execução geral do aplicativo​.

Número de referências globais

Embora o tempo de resposta seja uma característica essencial, também não devemos negligenciar o número de referências globais. Devemos lembrar que o acesso ao disco também costuma ser uma operação cara em termos de tempo de execução. No entanto, a eficiência do cache IRIS pode mascarar esse problema. Quero dizer com isso que, se muitas referências globais em cache forem acessadas simultaneamente, o tempo de resposta será excelente. Ainda assim, o desempenho cai consideravelmente assim que os dados acessados vêm de fora do cache. Em outras palavras, em um sistema onde são feitas várias solicitações ao mesmo tempo, o uso excessivo do acesso ao disco pode causar uma lentidão considerável. Um sistema de registro que mede referências de acesso global para cada solicitação também nos permite detectar solicitações HTTP que solicitam recursos em excesso. Ao identificar problemas desse tipo, os desenvolvedores podem fazer alterações para minimizar esse acesso (adicionando índices, otimizando consultas SQL, mudando a lógica etc.)

Número de linhas de código executadas

Contar o número de linhas de código executadas para cada solicitação nos oferece uma medida da complexidade e magnitude das operações realizadas. Essa medição nos ajuda a identificar consultas que executam muitas linhas de código, o que pode indicar partes do código que precisam de otimização. Na maioria dos casos, o problema está no número de referências globais. Porém, caso uma parte complexa do código seja apenas a manipulação de dados de memória com pouco acesso ao banco de dados, essa medição permitirá destacá-la (por exemplo, se houver um problema com loops).

Detecção de anomalias

Um registro do sistema também pode ser usado para detectar anomalias no desempenho da consulta de resposta. Ao registrar essas medições, é possível identificar solicitações fora do comum. Por exemplo, se uma consulta que costuma ser executada rapidamente de repente começa a demorar mais ou a acessar o disco em excesso, pode haver um problema que exige atenção imediata (como um maior tempo de resposta após a atualização de um aplicativo). Lembre-se de que a detecção precoce de anomalias nos ajuda a resolver problemas de desempenho rapidamente e garante uma boa experiência do usuário.

Pacote web-timing-logger

Recentemente, desenvolvi uma pequena ferramenta para a comunidade que nos permite registrar todas as solicitações HTTP recebidas. Se você tiver interesse, ela está disponível no Open Exchange. Essa ferramenta registra especialmente as principais métricas discutidas neste artigo: número de linhas de código executadas, número de referências globais e tempo de resposta. Ela também registra algumas informações sobre o autor da chamada que podem ser úteis para depuração:

  • Data e hora.
  • O usuário conectado.
  • Endereço IP do autor da chamada.
  • URL.
  • Namespace de execução.
  • Web app.
  • Nome da página (se aplicável).
  • URL sem parâmetros.

 

Além disso, também oferece a capacidade de integrar métricas personalizadas com SAM ("/api/monitor"), que permite incorporá-las no Prometheus e criar um painel de controle com o Grafana.
Há uma série de dados por web app, página ou rota (se for um aplicativo REST) ​​agregado por dia e quarto de hora:

  • Total de acessos: número de solicitações recebidas.
  • Tempo total: tempo de resposta cumulativa para todas as solicitações.
  • Tempo máximo: tempo de resposta mais lento.
  • Tempo média: tempo médio de resposta.

As mesmas métricas também estão disponíveis para referências globais e linhas de código executadas.

                                                                                                   Fichier:Prometheus software logo.svg — Wikipédia

Abaixo você pode ver um exemplo com as métricas ativadas nos web apps "/api/monitor/" e "/csp/sys/exp/":

webmeasure_average_gloref{id="/api/monitor/"} 903.5227272727272727
webmeasure_average_gloref{id="/api/monitor/metrics"} 903.5227272727272727
webmeasure_average_gloref{id="/csp/sys/exp/"} 1853.6875
webmeasure_average_gloref{id="/csp/sys/exp/%CSP.Broker.cls"} 1242.933333333333333
webmeasure_average_gloref{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 11015
webmeasure_average_gloref_current_quarter{id="/api/monitor/"} 903.5227272727272727
webmeasure_average_gloref_current_quarter{id="/api/monitor/metrics"} 903.5227272727272727
webmeasure_average_gloref_current_quarter{id="/csp/sys/exp/"} 1853.6875
webmeasure_average_gloref_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 1242.933333333333333
webmeasure_average_gloref_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 11015
webmeasure_average_lines{id="/api/monitor/"} 29365.5
webmeasure_average_lines{id="/api/monitor/metrics"} 29365.5
webmeasure_average_lines{id="/csp/sys/exp/"} 19415.5
webmeasure_average_lines{id="/csp/sys/exp/%CSP.Broker.cls"} 11570.73333333333333
webmeasure_average_lines{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 137087
webmeasure_average_lines_current_quarter{id="/api/monitor/"} 29365.5
webmeasure_average_lines_current_quarter{id="/api/monitor/metrics"} 29365.5
webmeasure_average_lines_current_quarter{id="/csp/sys/exp/"} 19415.5
webmeasure_average_lines_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 11570.73333333333333
webmeasure_average_lines_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 137087
webmeasure_average_timing_in_ms{id="/api/monitor/"} 27.27256818181818182
webmeasure_average_timing_in_ms{id="/api/monitor/metrics"} 27.27256818181818182
webmeasure_average_timing_in_ms{id="/csp/sys/exp/"} 16.6
webmeasure_average_timing_in_ms{id="/csp/sys/exp/%CSP.Broker.cls"} 9.94633333333333333
webmeasure_average_timing_in_ms{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 116.405
webmeasure_average_timing_in_ms_current_quarter{id="/api/monitor/"} 27.27256818181818182
webmeasure_average_timing_in_ms_current_quarter{id="/api/monitor/metrics"} 27.27256818181818182
webmeasure_average_timing_in_ms_current_quarter{id="/csp/sys/exp/"} 16.6
webmeasure_average_timing_in_ms_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 9.94633333333333333
webmeasure_average_timing_in_ms_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 116.405
webmeasure_max_lines{id="/api/monitor/"} 29498
webmeasure_max_lines{id="/api/monitor/metrics"} 29498
webmeasure_max_lines{id="/csp/sys/exp/"} 137087
webmeasure_max_lines{id="/csp/sys/exp/%CSP.Broker.cls"} 45208
webmeasure_max_lines{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 137087
webmeasure_max_lines_current_quarter{id="/api/monitor/"} 29498
webmeasure_max_lines_current_quarter{id="/api/monitor/metrics"} 29498
webmeasure_max_lines_current_quarter{id="/csp/sys/exp/"} 137087
webmeasure_max_lines_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 45208
webmeasure_max_lines_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 137087
webmeasure_max_timing{id="/api/monitor/"} 40.783
webmeasure_max_timing{id="/api/monitor/metrics"} 40.783
webmeasure_max_timing{id="/csp/sys/exp/"} 116.405
webmeasure_max_timing{id="/csp/sys/exp/%CSP.Broker.cls"} 66.458
webmeasure_max_timing{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 116.405
webmeasure_max_timing_current_quarter{id="/api/monitor/"} 40.783
webmeasure_max_timing_current_quarter{id="/api/monitor/metrics"} 40.783
webmeasure_max_timing_current_quarter{id="/csp/sys/exp/"} 116.405
webmeasure_max_timing_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 66.458
webmeasure_max_timing_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 116.405
webmeasure_total_gloref{id="/api/monitor/"} 39755
webmeasure_total_gloref{id="/api/monitor/metrics"} 39755
webmeasure_total_gloref{id="/csp/sys/exp/"} 29659
webmeasure_total_gloref{id="/csp/sys/exp/%CSP.Broker.cls"} 18644
webmeasure_total_gloref{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 11015
webmeasure_total_gloref_current_quarter{id="/api/monitor/"} 39755
webmeasure_total_gloref_current_quarter{id="/api/monitor/metrics"} 39755
webmeasure_total_gloref_current_quarter{id="/csp/sys/exp/"} 29659
webmeasure_total_gloref_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 18644
webmeasure_total_gloref_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 11015
webmeasure_total_hit{id="/api/monitor/"} 44
webmeasure_total_hit{id="/api/monitor/metrics"} 44
webmeasure_total_hit{id="/csp/sys/exp/"} 16
webmeasure_total_hit{id="/csp/sys/exp/%CSP.Broker.cls"} 15
webmeasure_total_hit{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 1
webmeasure_total_hit_current_quarter{id="/api/monitor/"} 44
webmeasure_total_hit_current_quarter{id="/api/monitor/metrics"} 44
webmeasure_total_hit_current_quarter{id="/csp/sys/exp/"} 16
webmeasure_total_hit_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 15
webmeasure_total_hit_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 1
webmeasure_total_lines{id="/api/monitor/"} 1292082
webmeasure_total_lines{id="/api/monitor/metrics"} 1292082
webmeasure_total_lines{id="/csp/sys/exp/"} 310648
webmeasure_total_lines{id="/csp/sys/exp/%CSP.Broker.cls"} 173561
webmeasure_total_lines{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 137087
webmeasure_total_lines_current_quarter{id="/api/monitor/"} 1292082
webmeasure_total_lines_current_quarter{id="/api/monitor/metrics"} 1292082
webmeasure_total_lines_current_quarter{id="/csp/sys/exp/"} 310648
webmeasure_total_lines_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 173561
webmeasure_total_lines_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 137087
webmeasure_total_timing_in_ms{id="/api/monitor/"} 1199.993
webmeasure_total_timing_in_ms{id="/api/monitor/metrics"} 1199.993
webmeasure_total_timing_in_ms{id="/csp/sys/exp/"} 265.6
webmeasure_total_timing_in_ms{id="/csp/sys/exp/%CSP.Broker.cls"} 149.195
webmeasure_total_timing_in_ms{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 116.405
webmeasure_total_timing_in_ms_current_quarter{id="/api/monitor/"} 1199.993
webmeasure_total_timing_in_ms_current_quarter{id="/api/monitor/metrics"} 1199.993
webmeasure_total_timing_in_ms_current_quarter{id="/csp/sys/exp/"} 265.6
webmeasure_total_timing_in_ms_current_quarter{id="/csp/sys/exp/%CSP.Broker.cls"} 149.195
webmeasure_total_timing_in_ms_current_quarter{id="/csp/sys/exp/%CSP.UI.Portal.SQL.Home.zen"} 116.405

Você deve ter notado que as métricas ilustradas acima são muito genéricas. Recomendo fortemente que você amplie e personalize suas métricas. É necessário para o monitoramento adequado dos aplicativos

Instalação usando ZPM

Se você deseja fazer uma instalação de teste e é usuário do Docker, recomendo que você revise esta seção para obter algumas informações práticas antes de passar para a próxima. O script de criação do contêiner configura o ambiente automaticamente.

A instalação é feita com o ZPM. Basta acessar o terminal IRIS e executar o seguinte:

zpm "install web-timing-logger”

Após a instalação, você precisa inicializar as configurações, então execute:

Do##class(dc.webtiming.Config).Initialize()

Por padrão, o log e as métricas de solicitações HTTP não estão ativos. Para ativá-los, siga as seguintes etapas:

Do##class(dc.webtiming.Config).SetLogEnabled(1)

Do##class(dc.webtiming.Config).SetMetricsEnabled(1)

Para SAM ("/api/monitor") expor métricas personalizadas, além de adicionar uma função ao web app /API/monitor, você deve registrar uma classe em SYS.Monitor.SAM.Config. Então, execute o seguinte comando:

Do##class(dc.webtiming.Config).ConfigureAPIMonitor()

Se você quiser usar esse utilitário em diversos web apps que são executados em diferentes namespaces, é fundamental mapear o pacote "dc.webtiming" e os globais "dc.webtiming*" em “%ALL”.  Para evitar fazer isso manualmente, use o método especificado abaixo:

Do##class(dc.webtiming.Config).AddToPercentAllNS()

Todas as ações mencionadas acima podem ser executadas em uma única linha com o próximo comando:

Do##class(dc.webtiming.Config).DefaultSetup()

Instalação usando Docker

O início com o Docker é clássico. Clone o repositório e inicie o contêiner:

git clone https://github.com/lscalese/iris-web-timing-logger.git
docker-compose up -d

Ativação em um web app

Agora que configuramos o sistema, ainda há um detalhe importante a ser configurado para que você possa registrar as medições. Para entender o que é preciso fazer, você deve saber como funciona o sistema.  Para acionar a medição e o registro, o web-timing-logger usa os eventos "OnStartRequest" e "OnEndRequest". Esses eventos são implementados na classe "dc.webtiming.CSPSessionEvents", que é uma subclasse de "%CSP.SessionEvents". Em seguida, cada web app precisa ser configurado com a classe de evento "dc.webtiming.CSPSessionEvents".

 

Se o seu web app já estiver usando outra classe de evento, não se preocupe! Basta adicionar as seguintes chamadas a essa classe:

No método OnStartRequest: 

Do##class(dc.webtiming.Events).OnStart()

e no método OnEndRequest:

Do##class(dc.webtiming.Events).OnEnd()

Isso adicionará a funcionalidade de medição e gravação às suas classes de evento existentes.

Faça essa configuração para todos os web apps que você deseja medir.

Se você tiver um sistema vazio e só quiser fazer alguns testes, use a configuração no web app /API/monitor. Como o acesso às métricas é estabelecido por uma chamada HTTP, elas também podem ser medidas para gerar logs.  Então, basta abrir seu navegador e acessar a página http://localhost:49165/api/monitor/metrics várias vezes (adapte com o número da sua porta). Você perceberá que as métricas "webmeasure" são alimentadas, e a tabela "dc_webtiming_log.Request" é preenchida com dados de solicitações HTTP:

SELECT *
FROM dc_webtiming_log.Request

Mesmo que Web-timing-logger facilite a identificação de pontos de entrada problemáticos em web apps, ele não oferece informações precisas sobre partes específicas do código que estão causando problemas.   Depois de identificar o ponto de entrada, você poderá usar outras ferramentas, como OEX ZProfile, desenvolvida por Dmitry Maslennikov. Ela pode realizar uma análise aprofundada do código que está sendo executado. Confira um artigo dedicado aqui.

Isso é tudo por hoje. É claro que poderíamos abordar outras coisas sobre o "web-timing-logger", como limpeza de logs, exemplo do painel de controle do Grafana ou até mesmo algumas consultas SQL interessantes. Espero que você tenha gostado do artigo e ele tenha dado ideias para o monitoramento dos seus aplicativos. Posso escrever uma continuação se você tiver interesse.

Até logo!

0
0 63
Artigo Danusa Calixto · Abr. 4, 2024 3m read

Neste artigo, vou explicar como autenticar, autorizar e auditar por código usando o web app CSP ao ativar/desativar e autenticar/remover autenticação de qualquer web app.

  • A demonstração online está disponível em cloud https://dappsecurity.demo.community.intersystems.com/csp/user/index.csp (SuperUser | SYS)
  • Recomendo assistir o vídeo antes de continuar https://www.youtube.com/watch?v=qFRa3njqDcA

Layout do aplicativo
 

Vamos começar com a autenticação

A autenticação verifica a identidade de qualquer usuário ou outra entidade que tenta se conectar ao InterSystems IRIS®. Como se costuma dizer, a autenticação é como você prova que é quem diz ser.

Há várias maneiras diferentes que um usuário pode ser autenticado. Cada uma é conhecida como um mecanismo de autenticação. O InterSystems IRIS aceita vários mecanismos de autenticação:

  • Kerberos — o protocolo Kerberos foi criado para oferecer uma autenticação segura a serviços em uma rede desprotegida. O Kerberos usa tickets para autenticar um usuário e evita a troca de senhas na rede.
  • Baseado no sistema operacional — a autenticação baseada no SO usa a identidade do sistema operacional para cada usuário identificar esse usuário para o InterSystems IRIS.
  • Autenticação da instância — com esse tipo de autenticação, o InterSystems IRIS solicita uma senha ao usuário e compara um hash de senhas fornecidas com um valor armazenado.
  • Lightweight Directory Access Protocol (LDAP) — com esse protocolo, o InterSystems IRIS autentica o usuário com base nas informações em um repositório central, conhecido como servidor LDAP.
  • Autenticação delegada — possibilita a criação de mecanismos de autenticação personalizados. O desenvolvedor do aplicativo controla totalmente o conteúdo do código de autenticação delegada.

Estou usando a Autenticação da instância. Para a criação do Usuário, podemos usar o seguinte comando objectscript  :

  &sql(CREATE USER TestUser IDENTIFY BY demo)

Criamos TestUser com a senha da demonstração


Auditoria

Ao criar o registro do usuário, também é adicionado o banco de dados de auditoria usando o comando objectscript abaixo:

Do $SYSTEM.Security.Audit("%System","%Security","UserChange","User:TestUser | Password:demo","Audit Log inserted from Data_APP_Security")


Leia a documentação relacionada (Guia de auditoria): https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AAUDIT


Autorização

Depois que a autenticação for concluída, precisamos criar funções, conceder Privilégios às funções e, em seguida, vincular as funções aos usuários (Autorização). Faremos isso em três etapas

Etapa 1: Crie uma função usando o seguinte comando objectscript. Estamos criando uma função ReadWrite

&sql(CREATE ROLE ReadWrite)


Etapa 2: conceda Privilégios SELECT,UPDATE,INSERT NA tabela à Função. Estamos atribuindo privilégios da tabela scw.Patient à função ReadWrite

&sql(GRANT SELECT,UPDATE,INSERT ON scw.Patient TO ReadWrite)


Etapa 3: Conceda a Função ao usuário. Estamos atribuindo a função ReadWrite ao TestUser 

&sql(GRANT ReadWrite To TestUser)

Ativar/desativar web app

Podemos ativar ou desativar o web app usando o seguinte código objectscript

New $Namespace
Set $Namespace = "%SYS"
Set App = ##class(Security.Applications).%OpenId("/terminal")
Set App.Enabled=0
Do App.%Save()

"/terminal" aqui é o nome do aplicativo. O aplicativo pode ser desativado definindo "App.Enabled" como 0 e ativado definindo o valor como 1


Autenticar/remover autenticação de web app

Podemos definir a autenticação usando o seguinte código objectscript

New $Namespace
Set $Namespace = "%SYS"
Set App = ##class(Security.Applications).%OpenId("/terminal")
Set App.AutheEnabled=0
Do App.%Save()

"/terminal" aqui é o nome do aplicativo. A autenticação pode ser definida usando a propriedade "App.AutheEnabled". Os seguintes valores numéricos podem ser definidos

property AutheEnabled as Security.Datatype.Authentication [ InitialExpression = 64 ];

Authentication and Session mechanisms enabled (CSP Only). Bit 2 = AutheK5API Bit 5 - AutheCache Bit 6 = AutheUnauthenticated Bit 11 = AutheLDAP Bit 13 = AutheDelegated Bit 14 = LoginToken Bit 20 = TwoFactorSMS Bit 21 = TwoFactorPW

Obrigado

0
0 101
Artigo Danusa Calixto · Mar. 13, 2024 3m read
   _________ ___ ____  
  |__  /  _ \_ _|  _ \ 
    / /| |_) | || |_) |
   / /_|  __/| ||  __/ 
  /____|_|  |___|_|    

Desde a versão 2021.1, o InterSystems IRIS começou a enviar com um ambiente de execução do python no kernel do motor. No entanto, não havia como instalar pacotes de dentro da instância. A principal vantagem do python é seu enorme ecossistema de pacotes. Com isso em mente, apresento meu projeto pessoal zpip, um wrapper de pip que pode ser chamado a partir do terminal iris.

O que é o zpip?

zpip é um wrapper para o pip do python que permite aos desenvolvedores adicionar pacotes rapidamente a uma instância pelo terminal do InterSystems IRIS.

Recursos

  • wrapper de pip do python para o InterSystems IRIS
  • Instalar/desinstalar pacotes do python
  • A instalação adiciona a palavra-chave zpip ao idioma

Instalando zpip

%SYS> zpm "install zpip"

Lista de tarefas

  • API chamável com status retornados

Usando zpip

Todos os comandos pip* são compatíveis. Porém, qualquer comando interativo exigirá que você use a versão não interativa do comando. Por exemplo, para desinstalar um pacote, você precisará usar o -y no comando para confirmar o processo.

Instalar pacotes do python com zpip

// Instale vários pacotes
// bibliotecas beautiful soup e requests
%SYS> zpip "install requests bs4"

... em ação:

%SYS>zpip "install emoji"

Processing /home/irisowner/.cache/pip/wheels/ae/80/43/3b56e58669d65ea9ebf38b9574074ca248143b61f45e114a6b/emoji-2.1.0-py3-none-any.whl
Installing collected packages: emoji
Successfully installed emoji-2.1.0

%SYS>

Especifique um diretório de instalação diferente:

// Instale em algum outro destino de pacote do python
$SYS> zpip "install --target '/durable/iconfig/lib/python' emoji"

Desinstalar um pacote do python

// Requer o -y!
%SYS>zpip "uninstall -y emoji"
Found existing installation: emoji 2.1.0
Uninstalling emoji-2.1.0:
  Successfully uninstalled emoji-2.1.0

Outros comandos úteis do pip

listar pacotes

// Listar pacotes
%SYS> zpip "list"
Package                      Version    
---------------------------- -----------
absl-py                      1.1.0      
argon2-cffi                  21.3.0     
argon2-cffi-bindings         21.2.0     
asttokens                    2.0.5      
astunparse                   1.6.3      
attrs                        21.4.0     
backcall                     0.2.0      
beautifulsoup4               4.11.1     
bleach                       5.0.0      
bs4                          0.0.1   
...

Limitações

  • Os comandos interativos não são compatíveis
    • use -y para desinstalações
  • A busca pode não funcionar dependendo da configuração do sistema
  • Usa a infraestrutura do pip do os subjacente, então sua instalação depende da versão do pip do os.
0
0 96
Artigo Danusa Calixto · Mar. 12, 2024 22m read

Olá, esta postagem foi escrita inicialmente para Caché. Em junho de 2023, finalmente a atualizei para IRIS. Se você está revisitando a postagem agora, a única mudança real foi a substituição do Caché pelo IRIS! Também atualizei os links para a documentação do IRIS e corrigi alguns erros de digitação e gramaticais. Aproveite :)


Nesta postagem, mostro estratégias para fazer backup do InterSystems IRIS usando o Backup Externo, incluindo exemplos da integração com soluções baseadas em cópias instantâneas. A maioria das soluções que vejo hoje são implantadas no Linux no VMware. Portanto, grande parte da postagem mostra as formas como as soluções integram a tecnologia de cópia instantânea VMware como exemplos.

Backup do IRIS - acompanha pilhas?

O backup online do IRIS está incluído na instalação do IRIS para backup contínuo dos bancos de dados do IRIS. Porém, há soluções de backup mais eficientes que você deve considerar ao ampliar os sistemas. O Backup Externo integrado com tecnologias de cópia instantânea é a solução recomendada para backup de sistemas, incluindo bancos de dados do IRIS.

Há alguma consideração especial para backup externo?

A documentação online do Backup Externo tem todos os detalhes. Uma consideração importante é:

"Para garantir a integridade cópia instantânea, o IRIS oferece métodos para congelar gravações em bancos de dados enquanto a cópia é criada. Somente as gravações físicas nos arquivos dos bancos de dados são congeladas durante a criação da cópia instantânea, permitindo que os processos do usuário continuem realizando atualizações na memória sem interrupções."

Também é importante observar que parte do processo de cópia em sistemas virtualizados causa uma pequena pausa no backup de uma VM, geralmente chamada de "tempo de stun". Ela costuma durar menos de um segundo, então não é percebida pelos usuários nem afeta a operação do sistema. Porém, em algumas circunstâncias, o stun pode durar mais tempo. Se o stun durar mais que o tempo limite de qualidade de serviço (QoS) para o espelhamento do banco de dados do IRIS, o nó de backup pensará que houve uma falha no primário e fará a tolerância a falhas. Mais adiante nesta postagem, explico como você pode revisar os tempos de stun caso precise alterar o tempo limite de QoS do espelhamento.


[Veja aqui uma lista de outras Plataformas de Dados da InterSystems e postagens da série de desempenho.](https://community.intersystems.com/post/capacity-planning-and-performance-series-index)

Leia também a Guia de Backup e Restauração da documentação online do IRIS para esta postagem.


Opções de backup

Solução de backup mínima - Backup Online do IRIS

Se você não tiver mais nada, ela vem incluída na plataforma de dados da InterSystems para backups de tempo de inatividade zero. Lembre-se: o backup online do IRIS só faz backup de arquivos dos bancos de dados do IRIS, capturando todos os blocos nos bancos de dados alocados para dados com a saída gravada em um arquivo sequencial. O Backup Online do IRIS é compatível com backups cumulativos e incrementais.

No contexto do VMware, o Backup Online do IRIS é uma solução de backup a nível de convidado. Como outras soluções de convidado, as operações do Backup Online do IRIS são praticamente as mesmas, quer o aplicativo seja virtualizado ou executado diretamente em um host. O Backup Online do IRIS precisa ser coordenado com um backup do sistema para copiar o arquivo de saída do backup online do IRIS para a mídia de backup e todos os outros sistemas de arquivos usados pelo seu aplicativo. No mínimo, o backup do sistema precisa incluir o diretório de instalação, o diário e os diretórios alternativos do diário, os arquivos do aplicativo e qualquer diretório com os arquivos externos usados pelo aplicativo.

O Backup Online do IRIS deve ser considerado como uma abordagem inicial para sites menores que querem implementar uma solução de baixo custo para fazer backup apenas de bancos de dados do IRIS ou backups ad hoc. Por exemplo, é útil na configuração do espelhamento. No entanto, como os bancos de dados crescem e o IRIS só costuma ser uma parte do cenário de dados do cliente, é uma prática recomendada combinar os Backups Externos com a tecnologia de cópia instantânea e utilitários de terceiros, o que possui vantagens como inclusão do backup de arquivos que não são dos bancos de dados, restaurações mais rápidas, visão de dados de toda a empresa e melhores ferramentas de gestão e catálogo.


Solução de backup recomendada - Backup Externo

Usando o VMware como exemplo, a virtualização no VMware adiciona funcionalidades e opções para proteger VMs inteiras. Depois de virtualizar uma solução, você encapsulará efetivamente seu sistema — incluindo o sistema operacional, o aplicativo e os dados —, tudo dentro de arquivos .vmdk (e alguns outros). Quando necessários, esses arquivos podem ser simples de gerenciar e usados para recuperar um sistema inteiro, o que difere muita da mesma situação em um sistema físico, onde você precisa recuperar e configurar os componentes separadamente – sistema operacional, drivers, aplicativos de terceiros, banco de dados, arquivos de bancos de dados etc.


# Cópia instantanea da VMware

A vSphere Data Protection (VDP) do VMware e outras soluções de backup de terceiros para o backup da VM, como Veeam ou Commvault, usam a funcionalidade de cópias instantâneas das máquinas virtuais do VMware para criar backups. Segue uma explicação de nível superior das cópias instantâneas do VMware. Veja a documentação do VMware para mais detalhes.

É importante lembrar que as cópias instantâneas são aplicados à VM inteira, e o sistema operacional e qualquer aplicativo ou mecanismo de banco de dados não sabem que a cópia está acontecendo. Além disso, lembre-se:

Sozinhas, as cópias instantâneas da VMware não são backups!

As cópias instantâneas permitem que o software de backup faça backups, mas eles não são backups por si sós.

O VDP e as soluções de backup de terceiros usam o processo de cópia do VMware em conjunto com o aplicativo de backup para gerenciar a criação e, mais importantemente, a exclusão da cópia instantânea. Em um nível superior, o processo e a sequência de eventos para um backup externo usando cópias instantâneas do VMware são os seguintes:

  • O software de backup de terceiros solicita que o host ESXi acione uma cópia instantânea do VMware.
  • Os arquivos .vmdk de uma VM são colocados em um estado somente leitura, e um arquivo delta .vmdk filho é criado para cada um dos arquivos .vmdk da VM.
  • A cópia na gravação é usada com todas as mudanças na VM gravadas nos arquivos delta. Quaisquer leituras são primeiro do arquivo delta.
  • O software de backup gerencia a cópia dos arquivos .vmdk pai somente leitura para o destino do backup.
  • Quando o backup é concluído, é feito o commit da cópia (os discos da VM retomam as gravações e atualizam os blocos nos arquivos delta gravados no pai).
  • A cópia instantânea do VMware é excluído agora.

As soluções de backup também usam outros recursos, como Changed Block Tracking (CBT), permitindo backups incrementais ou cumulativos para velocidade e eficiência (especialmente importante para a economia de espaço), e geralmente adicionam outras funções importantes, como deduplicação e compactação de dados, agendamento, montagem de VMs com endereços IP alterados para verificações de integridade etc., restaurações completas no nível da VM e do arquivo e gestão de catálogo.

As cópias instantâneas da VMware que não forem gerenciados adequadamente ou forem deixados em execução por um longo período podem usar armazenamento excessivo (quanto mais dados forem alterados, mais os arquivos delta continuarão a crescer) e deixar as VMs mais lentas.

Considere com cuidado antes de executar uma cópia instantânea manual em uma instância de produção. Por que você está fazendo isso? O que acontecerá se você reverter para quando a cópia instantânea foi criada? O que acontecerá com todas as transações do aplicativo entre a criação e a reversão?

Não tem problema se o seu software de backup criar e excluir uma cópia instantânea. A cópia instantânea deve existir apenas por um breve período. Uma parte fundamental da sua estratégia de backup será escolher um momento de baixo uso do sistema para minimizar qualquer impacto adicional nos usuários e no desempenho.

Considerações do banco de dados do IRIS para cópias instantâneas

Antes de obter a cópia instantânea, é preciso colocar o banco de dados no modo desativado. Assim, é realizado o commit de todas as gravações pendentes e o banco de dados fica em um estado consistente. O IRIS oferece métodos e uma API para fazer o commit e congelar (interromper) gravações no banco de dados por um breve período enquanto a cópia instantânea é criada. Assim, somente as gravações físicas nos arquivos do banco de dados são congeladas durante a criação da cópia instantânea, permitindo que os processos do usuário continuem realizando atualizações na memória sem interrupções. Depois que a cópia instantânea é acionada, as gravações no banco de dados são descongeladas e o backup continua copiando os dados para a mídia de backup. O tempo entre o congelamento e o descongelamento deve ser rápido (alguns segundos).

Além de pausar as gravações, o congelamento do IRIS também processa a troca de arquivos de diário e a gravação de um marcador de backup no diário. O arquivo de diário continua a ser gravado normalmente enquanto as gravações no banco de dados físico estão congeladas. Se o sistema falhar enquanto as gravações no banco de dados físico estiverem congeladas, os dados serão recuperados do diário normalmente durante a inicialização.

O diagrama a seguir mostra as etapas de congelamento e descongelamento com cópias instantâneas da VMware para criar um backup com uma imagem de banco de dados consistente.


Linha do tempo da cópia instantânea da VMware + congelamento/descongelamento do IRIS (não escalar)

image


Observe o breve período entre o congelamento e o descongelamento: apenas o suficiente para criar a cópia instantânea, e não copiar o pai somente leitura para o destino do backup​.


Resumo - Por que preciso congelar e descongelar o banco de dados do IRIS quando o VMware está criando uma cópia instantânea?

O processo de congelar e descongelar o banco de dados é fundamental para garantir a consistência e integridade dos dados. Isso ocorre porque:

Consistência dos dados: o IRIS pode escrever diários ou o WIJ ou fazer gravações aleatórias no banco de dados a qualquer momento. Uma cópia instantânea captura o estado da VM em um momento específico. Se o banco de dados estiver sendo ativamente gravado durante a cópia instantânea, isso poderá causar uma cópia com dados parciais ou inconsistentes. Congelar o banco de dados garante que todas as transações sejam concluídas e nenhuma transação nova seja iniciada durante a cópia, levando a um estado de disco consistente.

Desativação do sistema de arquivos: A tecnologia de cópia instantânea da VMware pode desativar o sistema de arquivos para garantir a consistência dele. No entanto, isso não abrange a consistência no nível do aplicativo ou do banco de dados. O congelamento do banco de dados garante que ele esteja em um estado consistente no nível do aplicativo, complementando o quiesce do VMware.

Redução do tempo de recuperação: a restauração de cópia instantânea obtida sem congelar o banco de dados pode exigir etapas adicionais, como o reparo do banco de dados ou verificações de consistência, o que pode aumentar significativamente o tempo de recuperação. O congelamento e descongelamento garantem que o banco de dados possa ser usado imediatamente após a restauração, diminuindo o tempo de inatividade.


Integração do congelamento e descongelamento do IRIS

O vSphere permite que um script seja chamado automaticamente em ambos os lados da criação da cópia instantânea. É quando são chamados o congelamento e descongelamento do IRIS. Observação: para essa funcionalidade funcionar corretamente, o host ESXi solicita que o sistema operacional convidado desative os discos pelas Ferramentas do VMware.

As ferramentas do VMware precisam ser instaladas no sistema operacional convidado.

Os scripts precisam obedecer regras rígidas de nome e localização. As permissões de arquivo também precisam ser definidas. Para o VMware no Linux, os nomes dos scripts são:

# /usr/sbin/pre-freeze-script
# /usr/sbin/post-thaw-script

Confira abaixo exemplos de scripts de congelamento e descongelamento que nossa equipe usa com o backup do Veeam para instâncias internas de laboratório de testes, mas eles também devem funcionar com outras soluções. Esses exemplos foram testados e usados no vSphere 6 e Red Hat 7.

Embora esses scripts possam ser usados como exemplos e ilustrem o método, você precisa validá-los para seus ambientes!

Exemplo de script pré-congelamento:

#!/bin/sh
#
# Script called by VMWare immediately prior to snapshot for backup.
# Tested on Red Hat 7.2
#

LOGDIR=/var/log
SNAPLOG=$LOGDIR/snapshot.log

echo >> $SNAPLOG
echo "`date`: Pre freeze script started" >> $SNAPLOG
exit_code=0

# Only for running instances
for INST in `iris qall 2>/dev/null | tail -n +3 | grep '^up' | cut -c5-  | awk '{print $1}'`; do

    echo "`date`: Attempting to freeze $INST" >> $SNAPLOG
    
    # Detailed instances specific log    
    LOGFILE=$LOGDIR/$INST-pre_post.log
    
    # Freeze
    irissession $INST -U '%SYS' "##Class(Backup.General).ExternalFreeze(\"$LOGFILE\",,,,,,1800)" >> $SNAPLOG $
    status=$?

    case $status in
        5) echo "`date`:   $INST IS FROZEN" >> $SNAPLOG
           ;;
        3) echo "`date`:   $INST FREEZE FAILED" >> $SNAPLOG
           logger -p user.err "freeze of $INST failed"
           exit_code=1
           ;;
        *) echo "`date`:   ERROR: Unknown status code: $status" >> $SNAPLOG
           logger -p user.err "ERROR when freezing $INST"
           exit_code=1
           ;;
    esac
    echo "`date`:   Completed freeze of $INST" >> $SNAPLOG
done

echo "`date`: Pre freeze script finished" >> $SNAPLOG
exit $exit_code

Exemplo de script de descongelamento:

#!/bin/sh
#
# Script called by VMWare immediately after backup snapshot has been created
# Tested on Red Hat 7.2
#

LOGDIR=/var/log
SNAPLOG=$LOGDIR/snapshot.log

echo >> $SNAPLOG
echo "`date`: Post thaw script started" >> $SNAPLOG
exit_code=0

if [ -d "$LOGDIR" ]; then

    # Only for running instances    
    for INST in `iris qall 2>/dev/null | tail -n +3 | grep '^up' | cut -c5-  | awk '{print $1}'`; do
    
        echo "`date`: Attempting to thaw $INST" >> $SNAPLOG
        
        # Detailed instances specific log
        LOGFILE=$LOGDIR/$INST-pre_post.log
        
        # Thaw
        irissession $INST -U%SYS "##Class(Backup.General).ExternalThaw(\"$LOGFILE\")" >> $SNAPLOG 2>&1
        status=$?
        
        case $status in
            5) echo "`date`:   $INST IS THAWED" >> $SNAPLOG
               irissession $INST -U%SYS "##Class(Backup.General).ExternalSetHistory(\"$LOGFILE\")" >> $SNAPLOG$
               ;;
            3) echo "`date`:   $INST THAW FAILED" >> $SNAPLOG
               logger -p user.err "thaw of $INST failed"
               exit_code=1
               ;;
            *) echo "`date`:   ERROR: Unknown status code: $status" >> $SNAPLOG
               logger -p user.err "ERROR when thawing $INST"
               exit_code=1
               ;;
        esac
        echo "`date`:   Completed thaw of $INST" >> $SNAPLOG
    done
fi

echo "`date`: Post thaw script finished" >> $SNAPLOG
exit $exit_code

Lembre-se de definir as permissões:

# sudo chown root.root /usr/sbin/pre-freeze-script /usr/sbin/post-thaw-script
# sudo chmod 0700 /usr/sbin/pre-freeze-script /usr/sbin/post-thaw-script

Teste de congelamento e descongelamento

Para testar se os scripts estão funcionando corretamente, você pode executar uma cópia instantânea manualmente em uma VM e verificar a saída do script. A captura de tela a seguir mostra a caixa de diálogo "Take VM Snapshot" (Tirar a cópia instantânea da VM) e as opções.

Desmarque- "Snapshot the virtual machine's memory" (Tirar a cópia instantânea da memória da máquina virtual).

Selecione - a caixa de seleção "Quiesce guest file system (Needs VMware Tools installed)", ou "Colocar o sistema de arquivos convidado em modo quiesced (as ferramentas do VMware precisam estar instaladas)", para pausar os processos em execução no sistema operacional convidado, deixando o conteúdo do sistema de arquivos em um estado consistente conhecido ao tirar a cópia instantânea.

Importante! Depois do teste, lembre-se de excluir a cópia instantânea!!!!

Se a sinalização quiesce for verdadeira e a máquina virtual estiver ligada ao tirar a cópia instantânea, as ferramentas do VMware serão usadas para o quiesce do sistema de arquivos na máquina virtual. O quiesce do sistema de arquivos é o processo de colocar os dados no disco em um estado adequado para backups. Esse processo pode incluir operações como a limpeza de buffers sujos no cache da memória do sistema operacional para o disco.

A saída a seguir mostra o conteúdo do arquivo de log $SNAPSHOT definido nos scripts de congelamento/descongelamento acima após executar um backup que inclui uma cópia instantânea como parte da sua operação.

Wed Jan  4 16:30:35 EST 2017: Pre freeze script started
Wed Jan  4 16:30:35 EST 2017: Attempting to freeze H20152
Wed Jan  4 16:30:36 EST 2017:   H20152 IS FROZEN
Wed Jan  4 16:30:36 EST 2017:   Completed freeze of H20152
Wed Jan  4 16:30:36 EST 2017: Pre freeze script finished

Wed Jan  4 16:30:41 EST 2017: Post thaw script started
Wed Jan  4 16:30:41 EST 2017: Attempting to thaw H20152
Wed Jan  4 16:30:42 EST 2017:   H20152 IS THAWED
Wed Jan  4 16:30:42 EST 2017:   Completed thaw of H20152
Wed Jan  4 16:30:42 EST 2017: Post thaw script finished

Esse exemplo mostra os 6 segundos decorridos entre o congelamento e o descongelamento (16:30:36-16:30:42). As operações dos usuários NÃO são interrompidas durante esse período. Você precisará coletar métricas dos seus próprios sistemas, mas, para um pouco de contexto, esse exemplo é de um sistema que está executando um benchmark de aplicativo em uma VM sem gargalos de IO e com uma média de mais de 2 milhões de glorefs/s, 170.000 de gloupds/s, 1.100 gravações físicas/s e 3.000 gravações por ciclo de daemon de gravação.

Lembre-se de que a memória não faz parte da cópia instantânea, portanto, ao reiniciar, a VM será reinicializada e recuperada. Os arquivos de banco de dados serão consistentes. Você não quer "retomar" um backup, e sim quer os arquivos em um momento conhecido. Então, você pode fazer o roll forward dos diários e quaisquer outras etapas de recuperação necessárias para o aplicativo e a consistência transacional assim que os arquivos forem recuperados.

Para proteção de dados adicional, a troca do diário pode ser feita por si só, e os diários podem ser armazenados em backup ou replicados em outro local, por exemplo, a cada hora.

Confira abaixo a saída de $LOGFILE nos scripts de congelamento/descongelamento acima, mostrando os detalhes do diário para a cópia instantânea.

01/04/2017 16:30:35: Backup.General.ExternalFreeze: Suspending system

Journal file switched to:
/trak/jnl/jrnpri/h20152/H20152_20170104.011
01/04/2017 16:30:35: Backup.General.ExternalFreeze: Start a journal restore for this backup with journal file: /trak/jnl/jrnpri/h20152/H20152_20170104.011

Journal marker set at
offset 197192 of /trak/jnl/jrnpri/h20152/H20152_20170104.011
01/04/2017 16:30:36: Backup.General.ExternalFreeze: System suspended
01/04/2017 16:30:41: Backup.General.ExternalThaw: Resuming system
01/04/2017 16:30:42: Backup.General.ExternalThaw: System resumed

Tempos de stun da VM

No ponto de criação de uma cópia instantânea da VM e após a conclusão do backup e o commit do snapshot, a VM precisa ser congelada por um breve período. Esse pequeno congelamento costuma ser chamado de "stun" da VM. Veja uma ótima postagem de blog sobre os tempos de stun aqui. Resumo os detalhes abaixo e os contextualizo para as considerações do banco de dados do IRIS.

Da postagem sobre os tempos de stun: "Para criar uma cópia instantânea da VM, é feito o 'stun' da VM para (i) serializar o estado do dispositivo no disco e (ii) encerrar o disco que está em execução e criar um ponto da cópia instantânea… Durante a consolidação, é feito o 'stun' da VM para encerrar os discos e colocá-los em um estado apropriado para a consolidação."

O tempo de stun é normalmente algumas centenas de milésimos. No entanto, se houver uma atividade muito alta de gravação em disco durante a fase de commit, o tempo de stun poderá ser de vários segundos.

Se a VM estiver participando do Espelhamento do Banco de Dados do IRIS como um membro Primário ou de Backup, e o tempo de stun for maior que o tempo limite de Qualidade de Serviço (QoS) do espelho, o espelho relatará a falha da VM Primária e assumirá o controle.

Atualização de março de 2018: Meu colega, Peter Greskoff, indicou que um membro espelho de backup poderia iniciar a tolerância a falhas na metade do tempo limite de QoS durante um stun da VM ou quando um membro espelho primário estiver indisponível.

Para conferir uma descrição detalhada das considerações de QoS e cenários de tolerância a falhas, consulte esta ótima postagem: Guia do Tempo Limite de Qualidade de Serviço para Espelhamento. Resumindo a questão dos tempos de stun da VM e QoS:

Se o espelho de backup não receber nenhuma mensagem do espelho primário dentro da metade do tempo limite de QoS, ele enviará uma mensagem para garantir que o primário ainda está ativo. Em seguida, o backup aguardará uma resposta da máquina primária pela outra metade do tempo de QoS. Se não houver resposta do primário, presume-se que ele está inativo, e o backup assumirá o controle.

Em um sistema ocupado, os diários são enviados continuamente do espelho primário para o espelho de backup, e o backup não precisa verificar se o primário ainda está ativo. No entanto, durante um período tranquilo — quando é mais provável que os backups ocorram —, se o aplicativo estiver ocioso, pode não haver mensagens entre o espelho primário e o de backup por mais da metade do tempo de QoS.

Confira abaixo o exemplo de Peter. Pense neste intervalo para um sistema ocioso com um tempo limite de QoS de 8 segundos e um tempo de stun da VM de 7 segundos:

  • :00 O primário dá um ping no árbitro com um keepalive, e o árbitro responde imediatamente
  • :01 O membro de backup envia o keepalive ao primário, e o primário responde imediatamente
  • :02
  • :03 Começa o stun da VM
  • :04 O primário tenta enviar o keepalive ao árbitro, mas não consegue até a conclusão do stun
  • :05 O membro de backup envia um ping ao primário, já que expirou metade da QoS
  • :06
  • :07
  • :08 O árbitro não recebe resposta do primário durante todo o tempo limite de QoS, então encerra a conexão
  • :09 O backup não recebeu uma resposta do primário e confirma com o árbitro que ele também perdeu a conexão, então assume o controle
  • :10 O stun da VM acaba, tarde mais!!

Leia também a seção Pitfalls and Concerns when Configuring your Quality of Service Timeout (Armadilhas e Preocupações ao Configurar o Tempo Limite de Qualidade de Serviço) na postagem do link acima para entender o equilíbrio de ter a QoS somente pelo tempo necessário. Ter a QoS por muito tempo, especialmente por mais de 30 segundos, também pode causar problemas.

Final da atualização de março de 2018:

Para obter mais informações sobre a QoS do Espelhamento, consulte também a documentação.

As estratégias para reduzir ao mínimo o tempo de stun incluem executar backups quando houver pouca atividade no banco de dados e configurar bem o armazenamento.

Como observado acima, ao criar uma cópia instantânea, há várias opções que você pode especificar. Uma delas é incluir o estado da memória na cópia - Lembre-se, o estado da memória NÃO é necessário para backups de bancos de dados do IRIS. Se estiver configurada a sinalização da memória, um dump do estado interno da máquina virtual será incluído na cópia. A criação de cópias instantâneas da memória demora muito mais. As cópias da memória são usados para reverter o estado de uma máquina virtual em execução para como estava quando a cópia foi obtida. Isso NÃO é necessário para o backup de arquivos de um banco de dados.

Ao tirar uma cópia instantânea da memória, será realizado o stun de todo o estado da máquina virtual. O tempo de stun varia.

Como observado anteriormente, para backups, a sinalização do quiesce precisa ser definida como verdadeira para cópias manuais ou pelo software de backup para garantir um backup consistente e utilizável.

Revisar tempos de stun em logs do VMware

A partir do ESXi 5.0, os tempos de stun das cópias são registrados no arquivo de log de cada máquina virtual (vmware.log) com mensagens semelhantes a:

2017-01-04T22:15:58.846Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 38123 us

Os tempos de stun estão em microssegundos. Então, no exemplo acima, 38123 us é 38123/1.000.000 segundos ou 0,038 segundos.

Para garantir que os tempos de stun estão dentro dos limites aceitáveis ou para solucionar problemas se você suspeitar que eles estão longos e causando problemas, baixe e revise os arquivos vmware.log da pasta da VM em que tem interesse. Depois de baixar, você pode extrair e ordenar o log usando os comandos Linux de exemplo abaixo.

Exemplo de download dos arquivos vmware.log

Há várias formas de baixar os logs de suporte, incluindo criando um pacote de suporte do VMware através do console de gerenciamento do vSphere ou da linha de comando do host ESXi. Consulte a documentação do VMware para ver todos os detalhes, mas abaixo está um método simples para criar e reunir um pacote de suporte bem menor que inclui o arquivo vmware.log para você revisar os tempos de stun.

Você precisará do nome longo do diretório onde os arquivos da VM estão localizados. Faça login no host ESXi onde a VM do banco de dados está em execução usando ssh e use o comando: vim-cmd vmsvc/getallvms  para listar os arquivos vmx e os nomes longos exclusivos associados a eles.

Por exemplo, o nome longo da VM do banco de dados de exemplo usada nesta postagem fica assim: 26 vsan-tc2016-db1 [vsanDatastore] e2fe4e58-dbd1-5e79-e3e2-246e9613a6f0/vsan-tc2016-db1.vmx rhel7_64Guest vmx-11

Em seguida, execute o comando para reunir e empacotar apenas os arquivos de log:
vm-support -a VirtualMachines:logs.

O comando dará a localização do pacote de suporte, por exemplo: To see the files collected, check '/vmfs/volumes/datastore1 (3)/esx-esxvsan4.iscinternal.com-2016-12-30--07.19-9235879.tgz'.

Agora você pode usar o sftp para transferir o arquivo para fora do host para processamento e análise adicional.

Nesse exemplo, após descompactar o pacote de suporte, acesse o caminho correspondente ao nome longo da VM do banco de dados. Por exemplo, nesse caso: <bundle name>/vmfs/volumes/<host long name>/e2fe4e58-dbd1-5e79-e3e2-246e9613a6f0.

Você verá vários arquivos de log numerados. O arquivo de log mais recente não tem número, ou seja, vmware.log. O log pode ter só algumas centenas de KB, mas há muitas informações. Porém, queremos os tempos de stun/unstun, que são fáceis de encontrar com grep. Por exemplo:

$ grep Unstun vmware.log
2017-01-04T21:30:19.662Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 1091706 us
--- 
2017-01-04T22:15:58.846Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 38123 us
2017-01-04T22:15:59.573Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 298346 us
2017-01-04T22:16:03.672Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 301099 us
2017-01-04T22:16:06.471Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 341616 us
2017-01-04T22:16:24.813Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 264392 us
2017-01-04T22:16:30.921Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 221633 us

Podemos ver dois grupos de tempos de stun no exemplo, um desde a criação da cópia instantânea e outro definido 45 minutos depois para cada disco quando a cópia foi excluído/consolidado (por exemplo, depois que o software de backup fez a cópia do arquivo vmx somente leitura). O exemplo acima mostra que a maioria dos tempos de stun é menor do que um segundo, mesmo que o tempo de stun inicial seja um pouco mais de um segundo.

Tempos de stun curtos não são perceptíveis para o usuário final. No entanto, os processos do sistema, como o Espelhamento do Banco de Dados do IRIS, verificam continuamente se uma instância está "ativa". Se o tempo de stun exceder o tempo limite de QoS do espelhamento, o nó poderá ser considerado fora de contato e "morto", e a tolerância a falhas será acionada.

Dica: para revisar todos os logs ou solucionar problemas, um comando útil é fazer o grep de todos os arquivos vmware*.log e procurar qualquer discrepância ou instância em que o tempo de stun chega próximo ao tempo limite de QoS. O seguinte comando canaliza a saída para awk para formatação:

grep Unstun vmware* | awk '{ printf ("%'"'"'d", $8)} {print " ---" $0}' | sort -nr


Resumo

Monitore seu sistema regularmente durante as operações normais para entender os tempos de stun e como eles podem afetar o tempo limite de QoS para HA, como o espelhamento. Como observado, as estratégias para reduzir ao mínimo o tempo de stun/unstun incluem executar backups quando houver pouca atividade no banco de dados e no armazenamento e configurar bem o armazenamento. Para monitoramento constante, os logs podem ser processados usando o VMware Log Insight ou outras ferramentas.

Em postagens futuras, revisitarei as operações de backup e restauração para as Plataformas de Dados da InterSystems. Por enquanto, caso você tenha algum comentário ou sugestão com base nos fluxos de trabalho dos seus sistemas, compartilhe nas seções de comentários abaixo.

0
0 89
Artigo Danusa Calixto · Mar. 12, 2024 9m read

Neste GitHub, você pode encontrar todas as informações sobre como usar um modelo de machine learning / IA do HuggingFace no Framework IRIS usando python.

1. iris-huggingface

Uso de modelos de machine learning no IRIS usando Python. Para modelos text-to-text, text-to-image e image-to-image.

Modelos de exemplo:

2. Instalação

2.1. Iniciando a produção

Na pasta iris-local-ml, abra um terminal e insira:

docker-compose up

Na primeira vez, pode levar alguns minutos para criar a imagem corretamente e instalar todos os módulos necessários para o Python.

2.2. Acesse a produção

Seguindo este link, acesse a produção: Acesse a produção

2.3. Encerrando a produção

docker-compose down

Como funciona

Por enquanto, alguns modelos talvez não funcionem com essa implementação, já que tudo é feito automaticamente, ou seja, não importa o modelo de entrada, tentaremos fazer com que funcione usando a biblioteca transformerspipeline.

Pipeline é uma ferramenta poderosa da equipe HuggingFace que analisa a pasta em que o modelo foi baixado e entende qual biblioteca deve usar entre PyTorch, Keras, Tensorflow ou JAX. Em seguida, ela carrega esse modelo usando AutoModel.
Então, ao inserir a tarefa, o pipeline sabe o que fazer com o modelo, tokenizer ou até extrator de características nessa pasta e gerencia a entrada automaticamente, tokeniza, processa, transfere para o modelo e retorna um resultado decodificado que podemos usar diretamente.

3. API do HuggingFace

Primeiro, você precisa iniciar a demonstração, usando o botão verde Start, ou use Stop e Start novamente para aplicar as mudanças nas configurações.

Em seguida, ao clicar na operação Python.HFOperation escolhida e selecionar na guia à direita action, você pode aplicar test à demonstração.

Na janela de test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.HFRequest

Para json, veja um exemplo de uma chamada para GPT2:

{
    "api_url":"https://api-inference.huggingface.co/models/gpt2",
    "payload":"Can you please let us know more details about your ",
    "api_key":"----------------------"
}

Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

OBSERVE que você precisa ter uma chave de API do HuggingFace antes de usar essa Operação (as chaves de API são gratuitas, basta fazer a inscrição na HF)

OBSERVE que você pode mudar o URL para testar outros modelos do HuggingFace. Talvez seja necessário mudar o payload.

Veja este exemplo:
sending hf reqhf reqhf resp

4. Use qualquer modelo da web

Nesta seção, vamos ensinar você a usar praticamente qualquer modelo da internet, HuggingFace ou não.

4.1. PRIMEIRO CASO: VOCÊ TEM SEU PRÓPRIO MODELO

Nesse caso, você precisa copiar e colar seu modelo, com config, tokenizer.json etc. dentro de uma pasta na pasta do modelo.
Caminho: src/model/yourmodelname/

Depois, você precisa acessar os parâmetros de Python.MLOperation.
Clique em Python.MLOperation e vá para settings na guia à direita. Depois, na parte Python e na parte %settings. Aqui, você pode inserir ou modificar quaisquer parâmetros (não se esqueça de pressionar apply depois de terminar).
Veja a configuração padrão para esse caso:
%settings

name=yourmodelname
task=text-generation

OBSERVE que qualquer configuração que não for name ou model_url entrará nas configurações PIPELINE.

Agora você pode clicar duas vezes na operação Python.MLOperation e executar o start. Você precisa ver na parte Log a inicialização do modelo.

Em seguida, criamos um PIPELINE utilizando transformers que usam o arquivo config na pasta como vimos antes.

Para chamar esse pipeline, clique na operação Python.MLOperation e selecione action na guia à direita. Você pode aplicar test à demonstração.

Na janela de test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.MLRequest

Para json, você precisa inserir todos os argumentos necessários para o modelo.
Aqui está um exemplo de uma chamada para GPT2:

{
    "text_inputs":"Unfortunately, the outcome",
    "max_length":100,
    "num_return_sequences":3
}

Clique em Invoke Testing Service (Invocar serviço de teste) e aguarde a operação do modelo.

Veja este exemplo:
sending ml req

Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

Veja este exemplo:
ml req

ml resp

4.2. SEGUNDO CASO: VOCÊ QUER BAIXAR UM MODELO DO HUGGINGFACE

Nesse caso, você precisa encontrar o URL do modelo no HuggingFace.

4.2.1. Configurações

Depois, você precisa acessar os parâmetros de Python.MLOperation.
Clique em Python.MLOperation e vá para settings na guia à direita. Depois, na parte Python e na parte %settings. Aqui, você pode inserir ou modificar quaisquer parâmetros (não se esqueça de pressionar apply depois de terminar).
Veja um exemplo de configuração para alguns modelos que encontramos no HuggingFace:

%settings para gpt2

model_url=https://huggingface.co/gpt2
name=gpt2
task=text-generation

%settings para camembert-ner

name=camembert-ner
model_url=https://huggingface.co/Jean-Baptiste/camembert-ner
task=ner
aggregation_strategy=simple

%settings para bert-base-uncased

name=bert-base-uncased
model_url=https://huggingface.co/bert-base-uncased
task=fill-mask

%settings para detr-resnet-50

name=detr-resnet-50
model_url=https://huggingface.co/facebook/detr-resnet-50
task=object-detection

%settings para detr-resnet-50-protnic

name=detr-resnet-50-panoptic
model_url=https://huggingface.co/facebook/detr-resnet-50-panoptic
task=image-segmentation

OBSERVE que qualquer configuração que não for name ou model_url entrará nas configurações PIPELINE. Então, no segundo exemplo, o pipeline camembert-ner requer a especificação de aggregation_strategy e task, enquanto gpt2 requer apenas uma task.

Veja este exemplo:
settings ml ope2

Agora você pode clicar duas vezes na operação Python.MLOperation e executar o start.
Você precisa ver na parte Log a inicialização e o download do modelo.
OBSERVAÇÃO Você pode atualizar esses logs a cada x segundos para ver o avanço dos downloads. dl in real time

Em seguida, criamos um PIPELINE utilizando transformers que usam o arquivo config na pasta como vimos antes.

4.2.2. Testes

Para chamar esse pipeline, clique na operação Python.MLOperation e selecione action na guia à direita. Você pode aplicar test à demonstração.

Na janela de test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.MLRequest

Para json, você precisa inserir todos os argumentos necessários para o modelo.
Aqui está um exemplo de uma chamada para GPT2 (Python.MLOperation):

{
    "text_inputs":"George Washington lived",
    "max_length":30,
    "num_return_sequences":3
}

Aqui está um exemplo de uma chamada para Camembert-ner (Python.MLOperation2):

{
    "inputs":"George Washington lived in washington"
}

Aqui está um exemplo de uma chamada para bert-base-uncased (Python.MLOperation3):

{
    "inputs":"George Washington lived in [MASK]."
}

Aqui está um exemplo de uma chamada para detr-resnet-50 usando um URL online (Python.MLOperationDETRRESNET):

{
    "url":"http://images.cocodataset.org/val2017/000000039769.jpg"
}

Aqui está um exemplo de uma chamada para detr-resnet-50-panoptic usando um URL como caminho (Python.MLOperationDetrPanoptic):

{
    "url":"/irisdev/app/misc/000000039769.jpg"
}

Clique em Invoke Testing Service (Invocar serviço de teste) e aguarde a operação do modelo.
Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

OBSERVE que, após fazer pela primeira vez o download de um modelo, a produção não fará o download novamente, mas usará os arquivos em cache encontrados em src/model/TheModelName/.
Se alguns arquivos estiverem ausentes, a Produção fará o download novamente.

Veja este exemplo:
sending ml reqml reqml resp

Veja este exemplo:
sending ml reqml resp

5. Solução de problemas

Se você tiver problemas, a leitura é o primeiro conselho que podemos dar a você. A maioria dos erros são facilmente compreendidos apenas ao ler os logs, pois quase todos os erros são capturados por um try/catch e registrados.

Se você precisar instalar um novo módulo ou dependência do Python, abra um terminal dentro do contêiner e digite, por exemplo: "pip install new-module"
Há várias formas de abrir um terminal,

  • Se você usa os plugins da InterSystems, pode clicar na barra abaixo no VSCode, que se parece com docker:iris:52795[IRISAPP], e selecionar Open Shell in Docker (Abrir Shell no Docker).
  • Em qualquer terminal local, digite: docker-compose exec -it iris bash
  • No Docker-Desktop, encontre o contêiner IRIS e clique em Open in terminal (Abrir no terminal)

Alguns modelos talvez exijam algumas alterações no pipeline ou nas configurações, por exemplo. É sua responsabilidade adicionar as informações corretas nas configurações e na solicitação.

6. Conclusão

Depois disso, você poderá usar qualquer modelo que de precisa ou possui no IRIS.
OBSERVE que você pode criar uma Python.MLOperation para cada um dos seus modelos e ter todos ativados ao mesmo tempo.

0
0 166
Artigo Danusa Calixto · Dez. 6, 2023 2m read

Com certeza, você já se deparou com esta situação:

  • Há um bug em um Sistema que você não consegue reproduzir localmente
  • Você precisa executar algumas linhas na instância afetada
  • Você ganha acesso completo ao Portal de Gerenciamento de Sistemas
  • Mas não há terminal, console nem acesso com o Studio, Atelier ou VSCode
  • Como executar algumas linhas para teste ???
  • Acesse o SMP / Explorer / guia SQL= Execute Query
    •  
    •  
  • Agora crie um procedimento armazenado com o código necessário
    • Não há limite de complexidade. Eu só crio um simples com resultado previsível.
    • CREATE PROCEDURE RUN.ISOS()
      

LANGUAGE OBJECTSCRIPT { For i=1:1:20 write i," > "   Write "
THANKS !" }

  • Clique em EXECUTE para ver um novo procedimento *    
    •  
  • Em seguida, examine esse novo procedimento e execute-o *  
    •  
  • Ele é ativado com outra execução *  
    •  
  • e este é o resultado *
    •  
  • como você é um especialista bem instruído, limpa o ambiente depois de terminar  
    • DROP PROCEDURE RUN.ISOS
    •  

Espero que isso ajude você no futuro.
Documentação

0
0 76
Artigo Danusa Calixto · Dez. 5, 2023 5m read

Deixe-me apresentar meu novo projeto, que é o irissqlcli, um REPL (Read-Eval-Print Loop)  para o InterSystems IRIS SQL 

  • Destaque de sintaxe
  • Sugestões (tabelas, funções)
  • 20+ formatos de saída
  • Suporte ao stdin
  • Saída em arquivos 

Instale com o pip

pipinstallirissqlcli

Ou execute com o docker

dockerrun-itcaretdev/irissqlcliirissqlcliiris://_SYSTEM:SYS@host.docker.internal:1972/USER

Conecte ao IRIS

$ irissqlcli iris://_SYSTEM@localhost:1972/USER -W
Password for _SYSTEM:
Server:  InterSystems IRIS Version 2022.3.0.606 xDBC Protocol Version 65
Version: 0.1.0
[SQL]_SYSTEM@localhost:USER> select $ZVERSION
+---------------------------------------------------------------------------------------------------------+
| Expression_1                                                                                            |
+---------------------------------------------------------------------------------------------------------+
| IRIS for UNIX (Ubuntu Server LTS for ARM64 Containers) 2022.3 (Build 606U) Mon Jan 30202309:05:12 EST |
+---------------------------------------------------------------------------------------------------------+
1 row in set
Time: 0.063s
[SQL]_SYSTEM@localhost:USER> help
+----------+-------------------+------------------------------------------------------------+
| Command  | Shortcut          | Description                                                |
+----------+-------------------+------------------------------------------------------------+
| .exit    | \q                | Exit.                                                      |
| .mode    | \T                | Change the table format used to output results.            |
| .once    | \o [-o] filename  | Append next result to an output file (overwrite using -o). |
| .schemas | \ds               | List schemas.                                              |
| .tables  | \dt [schema]      | List tables.                                               |
| \e       | \e                | Edit command with editor (uses $EDITOR).                   |
| help     | \?                | Show this help.                                            |
| nopager  | \n                | Disable pager, print to stdout.                            |
| notee    | notee             | Stop writing results to an output file.                    |
| pager    | \P [command]      | Set PAGER. Print the query results via PAGER.              |
| prompt   | \R                | Change prompt format.                                      |
| quit     | \q                | Quit.                                                      |
| tee      | tee [-o] filename | Append all results to an output file (overwrite using -o). |
+----------+-------------------+------------------------------------------------------------+
Time: 0.012s
[SQL]_SYSTEM@localhost:USER>

$ irissqlcli--helpUsage: irissqlcli[OPTIONS][URI][USERNAME]

Options: -h, --hostTEXTHostaddressoftheIRISinstance. -p, --portINTEGERPortnumberatwhichtheIRISinstanceislistening. -U, --usernameTEXTUsernametoconnecttotheIRISinstance. -u, --userTEXTUsernametoconnecttotheIRISinstance. -W, --passwordForcepasswordprompt. -v, --versionVersionofirissqlcli. -n, --nspaceTEXTnamespacenametoconnectto. -q, --quietQuietmode, skipintroonstartupandgoodbyeonexit. -l, --logfileFILENAMELogeveryqueryanditsresultstoafile. --irissqlclircFILELocationofirissqlclircfile. --auto-vertical-outputAutomaticallyswitchtoverticaloutputmodeiftheresultiswiderthantheterminalwidth. --row-limitINTEGERSetthresholdforrowlimitprompt. Use 0 todisableprompt. -t, --tableDisplaybatchoutputintableformat. --csvDisplaybatchoutputinCSVformat. --warn / --no-warnWarnbeforerunningadestructivequery. -e, --executeTEXTExecutecommandandquit. --helpShowthismessageandexit.

ou no modo Python Embedded (%Service_CallIn precisa estar ativada)

$ irissqlcliiris+emb:///USERServer:  IRISforUNIX (UbuntuServerLTSforARM64Containers) 2022.2 (Build 368U) FriOct 21 2022 16:39:41EDTVersion: 0.1.0[SQL]irisowner@/usr/irissys/:USER>

Ele é compatível com o stdin, então você pode criar um pipe de um arquivo SQL com várias consultas SQL e comandos irissqcli. Por exemplo, este comando produzirá 3 arquivos em formatos diferentes (de mais de 20 formatos disponíveis)

$ cat <<EOF | irissqlcli iris://_SYSTEM:SYS@localhost:1972/USER

.mode csv; tee -o test.csv; select top 10 TABLE_SCHEMA,TABLE_NAME from information_schema.tables orderby TABLE_SCHEMA,TABLE_NAME; notee;

.mode latex; tee -o test.tex; select top 10 TABLE_SCHEMA,TABLE_NAME from information_schema.tables orderby TABLE_SCHEMA,TABLE_NAME; notee;

.mode html; tee -o test.html; select top 10 TABLE_SCHEMA,TABLE_NAME from information_schema.tables orderby TABLE_SCHEMA,TABLE_NAME; notee;

EOF

Além disso, é possível executar um terminal da Web com o docker

docker run -d --name irissqlcli \
  --restart always \
  -p 7681:7681\
  caretdev/irissqlcli-web irissqlcli iris://_SYSTEM:SYS@host.docker.internal:1972/USER

http://localhost:7681/

E com docker-compose

version: '3'
services:
  iris:
    image: intersystemsdc/iris-community
    ports:
      - 1972
      - 52773
    command:
      - -a
      - '##class(Security.Users).UnExpireUserPasswords("*")'
  cli:
    image: caretdev/irissqlcli-web
    ports:
      - 7681:7681
    environment:
      - IRIS_HOSTNAME:iris
      - IRIS_PORT=1972
      - IRIS_NAMESPACE=USER
      - IRIS_USERNAME=_SYSTEM
      - IRIS_PASSWORD=SYS

Por favor, vote no projeto no concurso

0
0 103
Artigo Danusa Calixto · Dez. 4, 2023 5m read

csp-log-tutorial

Pré-requisitos

Confira se o git está instalado.

Criei uma pasta git dentro do diretório mgr do IRIS. Cliquei com o botão direito do mouse na pasta git e escolhi Git Bash Here no menu de contexto.

git clone https://github.com/oliverwilms/csp-log-tutorial.git

Clone meu repositório do GitHub csp-log-tutorial se quiser testar você mesmo.

Vou descrever neste tutorial como tento usar arquivos access.log e CSP.log em pods webgateway para monitorar solicitações e respostas.

Minha equipe trabalha com contêineres IRIS executados na Red Hat OpenShift Container Platform (Kubernetes) da AWS. Implantamos três pods webgateway que recebem solicitações por um Balanceador de Carga de Rede. As solicitações são processadas em uma produção da InterOperability que é executada em três pods de computação. Usamos a produção do Message Bank que é executada em pods de dados espelhados como um local para analisar todas as mensagens processadas por qualquer pod de computação.

Testamos nossas interfaces usando pods alimentadores para enviar várias mensagens de solicitação ao Balanceador de Carga de Rede. Enviamos 100 mil mensagens e testamos quanto tempo leva para processar todas elas no Message Bank e gravar as respostas nos alimentadores. O número de mensagens depositadas no Message Bank e respostas recebidas pelos alimentadores corresponderam ao número de mensagens de entrada.

Recentemente, recebemos a solicitação para testar os failovers dos pods e da zona de disponibilidade (AZ). Excluímos os pods individuais à força ou não e com ou sem período de carência. Simulamos a falha da zona de disponibilidade ao negar todo o tráfego recebido e enviado a uma subrede (uma das três zonas de disponibilidade) pelo console da AWS enquanto os alimentadores enviam várias mensagens de solicitação ao Balanceador de Carga de Rede. É bastante desafiador contabilizar todas as mensagens enviadas pelos alimentadores.

Outro dia, quando um alimentador enviou 5 mil mensagens, simulamos a falha da AZ. O alimentador recebeu 4933 respostas. O Message Bank estava com 4937 mensagens.

Armazenamos access.log e CSP.log no diretório de dados dos pods webgateway. Adicionamos esta linha ao Dockerfile da nossa imagem webgateway:

RUN sed -i 's|APACHE_LOG_DIR=/var/log/apache2|APACHE_LOG_DIR=/irissys/data/webgateway|g' /etc/apache2/envvars

Definimos o Nível do Log de Eventos no Web Gateway como Ev9r. screenshot

Criei os subdiretórios data0, data1 e data2 para nossos três pods webgateway. Copiei os arquivos CSP.log e access.log dos nossos três pods webgateway armazenados em volumes persistentes:

oc cp iris-webgateway-0:/irissys/data/webgateway/access.log data0/access.log
oc cp iris-webgateway-1:/irissys/data/webgateway/access.log data1/access.log
oc cp iris-webgateway-2:/irissys/data/webgateway/access.log data2/access.log
oc cp iris-webgateway-0:/irissys/data/webgateway/CSP.log data0/CSP.log
oc cp iris-webgateway-1:/irissys/data/webgateway/CSP.log data1/CSP.log
oc cp iris-webgateway-2:/irissys/data/webgateway/CSP.log data2/CSP.log

Acabei com três subdiretórios, cada um com arquivos access.log e CSP.log.

Contamos o número de solicitações processadas em qualquer pod webgateway usando este comando:

cat access.log | grep InComingOTW | wc -l

Contamos o número de solicitações e respostas registradas em CSP.log usando este comando:

cat CSP.log | grep InComingOTW | wc -l

Geralmente, esperamos o dobro de linhas no CSP.log em comparação com o access.log. Às vezes, encontramos mais linhas em CSP.log do que o dobro esperado do número de linhas em access.log. Lembro de ver menos linhas do que o esperado em CSP.log em comparação com o que estava em access.log pelo menos uma vez. Suspeitamos que isso tenha ocorrido devido às 500 respostas registradas em access.log, que não foram registradas em CSP.log de maneira adequada, porque o pod webgateway foi encerrado.

Como analisar várias linhas de solicitações e explicar o que aconteceu?

Criei as classes persistentes otw.wgw.apache e otw.wgw.csp para importar linhas de access.log e CSP.log. access.log contém uma linha por solicitação, incluindo o status da resposta. CSP.log contém linhas separadas para solicitações e respostas.

Abra o terminal do IRIS e importe as classes no diretório src do repositório csp-log-tutorial que clonamos antes:

Set src="C:\InterSystems\IRISHealth\mgr\git\csp-log-tutorial\src"
Do $system.OBJ.LoadDir(src,"ck",,1)

Se você não tiver seu próprio arquivo CSP.log para analisar, é possível importar o arquivo do repositório csp-log-tutorial:

Set pFile="C:\InterSystems\IRISHealth\mgr\git\csp-log-tutorial\wg2_20230314_CSP.log"
Do ##class(otw.wgw.csp).ImportMessages(pFile,.pLines,.pFilter,1)

pLines e pFilter são parâmetros de saída que não são tão importantes no momento. pImport controla se Extent é excluído antes de importar os dados.

Depois de importar os dados, podemos executar consultas SQL como esta:

SELECT count(*) FROM otw_wgw.csp where wgEvent='WebGateway.ProcessRequest'

Se o número retornado for ímpar, isso indica que há uma divergência entre as solicitações e as respostas.

Podemos executar a próxima consultar para identificar os nomes de arquivos nas solicitações que não têm uma resposta correspondente:

select zFilename, count(*) from otw_wgw.csp group by zFilename having count(*) = 1

Observe que eu usei o método CalcFilename para definir a propriedade zFilename antes de salvar uma linha importada do arquivo CSP.log.

Também incluí um arquivo access.log de amostra, que podemos importar assim: Se você não tiver seu próprio arquivo CSP.log para analisar, é possível importar o arquivo do repositório csp-log-tutorial:

Set pFile="C:\InterSystems\IRISHealth\mgr\git\csp-log-tutorial\wg2_20230314_access.log"
Do ##class(otw.wgw.apache).ImportMessages(pFile,.pLines,.pFilter,1)

Podemos executar esta consulta para obter o número de mensagens relacionadas a esse tutorial:

SELECT count(*) FROM otw_wgw.apache where Text like '%tutorial%'

O que mais quero fazer se tiver tempo?

Gostaria de combinar os dados das tabelas apache e csp e possivelmente incluir os dados reunidos dos pods de computação.

Acho que posso usar os dados em access.log para determinar quando houve uma interrupção em um pod webgateway.

0
0 57
Artigo Danusa Calixto · Dez. 4, 2023 9m read

Power BI

Conectando a uma origem de dados

Para conectar a AtScale, vamos usar o banco de dados do SQL Server Analysis Services. Vamos abri-lo no editor do Power Query. Para fazer isso, selecione Transform Data (Transformar dados) em Home.

Na janela exibida, acesse Home, abra New Source (Nova origem) e selecione Analysis Services.

Na linha do Server, você precisa especificar o link MADX para o projeto publicado na AtScale. Você também pode indicar imediatamente o nome do projeto na linha do banco de dados se quiser.

Em seguida, selecione o tipo de autorização Basic e especifique o login/senha da AtScale.

Em Navigator, você precisa especificar as medidas e dimensões necessárias (se não houver conexão entre os campos, você não conseguirá criar uma consulta correta). Também é recomendável dividir o cubo em várias tabelas, dependendo da tarefa. Isso ajudará você a melhorar o desempenho e evitar erros.

Para configurar atualizações automáticas, você precisa usar o Gateway do Power BI e a autorização do Windows. Neste artigo, vamos pular essas etapas. 

No entanto, você pode ler mais sobre esse assunto na documentação da AtScale.

Recursos da criação de consultas no Power Query.

Depois de adicionar as colunas, você pode fazer alterações na tabela (modificar o nome da coluna, o tipo de dados, adicionar/alterar colunas, substituir valores etc.).
Por exemplo, você pode alterar o nome de uma coluna. Para fazer isso, clique duas vezes no nome da coluna. É recomendável verificar se não há campos em branco nos valores numéricos. Todos os valores em branco precisam ser marcados como null. Se você tiver campos vazios, basta sobrepor o tipo de campo. Para isso, clique no ícone de tipo à esquerda do nome da coluna e escolha o tipo necessário.

O Power Query pode não identificar corretamente o tipo de dados. Neste exemplo, ele reconheceu incorretamente o formato de dados.


Para corrigir isso, apontamos um formato de dados específico. Para fazer isso, clique no íconede tipo de dados, Use Locale…

Em nosso caso, vamos escolher Date e a localidade English (United States).

Agora os dados são exibidos corretamente.

Você pode saber mais sobre como trabalhar no Power Query na documentação oficial.

Trabalhando no Power BI e criando visualizações.

Criando uma tabela de dados usando funções DAX. 

Para que nossas tabelas sejam relatadas por data, vamos criar um calendário com base nas datas disponíveis usando a linguagem DAX integrada.

Uma forma de criar uma tabela de dados é usando a função DAX integrada recomendada, já que pode haver datas adicionais de início e término, como aniversários de funcionários, então é melhor configurá-las manualmente no CALENDAR. Essas funções retornam todos os dias entre as datas mínima e máxima.

Calendar = CALENDAR(<start_date>, <end_date>))

Agora vamos adicionar uma coluna com o ano e o nome do mês desejado. Você pode usar uma hierarquia de datas para obter o ano e o nome do mês. Em Column Tools, clique no botão New Column e escreva a fórmula.

Month = 'Calendar'[Date].[Year]

Em DAX, a fórmula é precedida pelo nome da coluna. O = indica o início de uma fórmula. Em seguida, a própria fórmula é escrita. Em nosso caso, simplesmente tiramos o [Year] da data do calendário. É sempre recomendável escrever o nome da tabela, mas você pode só escrever [Date].[Year]. O Power BI consultará a coluna Date existente dentro da tabela.
Vamos adicionar uma coluna no formato (MMM-AAAA). Para fazer isso, vamos escrever a função FORMAT .
Month-Year = FORMAT('Calendar'[Date], "MMM-YYYY").

No entanto, como Month e Month-Year são campos de texto, eles serão colocados em ordem alfabética. Vamos criar colunas para a classificação correta: MonthNum com o valor numérico do mês para a coluna Month, e MonthYearNum para a coluna Month-Year. 

MonthYearNum = FORMAT('Calendar'[Date], "YYYYMM")

Agora precisamos definir a coluna de ordenação. Acesse Column Tools selecione Sort by e selecione a coluna necessária. Vamos realizar a mesma manipulação para o resto das colunas com texto. 

Para entender melhor as fórmulas DAX, você pode fazer aulas no site oficial da Microsoft.

Gerenciando dados

A visualização Model no Power BI Desktop permite que você defina a relação entre as tabelas ou os itens visualmente. Nesse caso, duas ou mais tabelas serão vinculadas, porque elas contêm dados relacionados. Assim, os usuários podem acessar dados relacionados em vários tablets. Na visualização Model, você pode ver uma representação esquemática dos dados.

É muito fácil adicionar e remover associações. Para criar uma associação, arraste os campos que você quer associar entre as tabelas. Para remover uma associação, clique com o botão direito e selecione Delete.

Para entender as associações de dados em mais detalhes, em Home, acesse Manage relationships (Gerenciar relações). A caixa de diálogo Manage mostra as associações como uma lista, em vez de um diagrama visual. Nessa caixa de diálogo, você pode selecionar Autodiscover (Descoberta automática) para encontrar relações entre dados novos ou atualizados. Selecione Edit para modificar as associações manualmente. A seção de edição contém parâmetros adicionais que permitem definir a multiplicidade e direção da filtragem cruzada para associações.

Suas opções de cardinalidade são explicadas na tabela a seguir.

Opções de cardinalidade

Exemplo

Muitos para um

A relação padrão mais comum. Uma coluna na mesma tabela pode ter mais de uma instância de um valor. A tabela associada (ou tabela de consulta) só tem uma única instância do valor.

Um para um

Uma coluna em uma tabela só tem uma única instância de um valor específico e outra tabela relacionada só tem uma instância de um valor específico.

Geralmente, recomendamos reduzir o uso de relações bidirecionais. Elas podem ter um impacto negativo no desempenho de consultas do modelo e, possivelmente, oferecer experiências confusas para os usuários dos relatórios.

A definição de relações precisas entre seus dados permite que você crie cálculos complexos em vários elementos de dados.

Veja mais informações sobre modelos de dados aqui.

Slicers

Um filtro simples que pode ser usado diretamente na página de um relatório é chamado de slicer. Os slicers oferecem dicas de como você pode filtrar os resultados em elementos visuais na página de um relatório. Há diferentes tipos de slicers: numéricos, por categoria e por data. Os slicers ajudam você a filtrar facilmente todos os elementos visuais em uma página de uma só vez.

Esse GIF mostra o trabalho de uma segmentação padrão. Você pode configurar várias seleções para selecionar várias opções sem Ctrl.

Para fazer isso, selecione slicer. Em seguida, no painel Visualizations, escolha a guia Format visual . Abra  Selection, e ative a Seleção múltipla com Ctrl.

Você também pode mudar a aparência do slicer. Para isso, selecione a seta para baixo no canto superior direito do elemento do slicer.

 

 

Adicionando um elemento visual à página

Para adicionar um elemento visual, selecione-o em Visualizations

Vamos adicionar um gráfico de colunas empilhadas.

Agora, precisamos selecionar os campos que queremos exibir. Vamos adicionar o campo Month-Year de Calendar e outro valor numérico da sua tabela.
Este deve ser o resultado.

Para truncar os dados, vamos adicionar um filtro por data. Vamos extrair o campo Date de Calendar e mudar o tipo de visualização para slicer. Em seguida, vamos remover a hierarquia padrão e usar o formato de dados comum. Depois, devemos mudar imediatamente o tipo de visualização para uma data relativa.

Agora, podemos aplicar um filtro para exibir os últimos 6 meses.

Você pode mudar a visualização na guia de formatação. Cada elemento visual tem parâmetros especiais. Leia mais sobre isso aqui

Também há uma guia com opções gerais, como título e plano de fundo.

Vamos adicionar mais algumas visualizações e mudar o visual delas um pouco.

Agora, temos um exemplo de painel de controle simples.

Publicando um relatório em app.powerbi.com

Os relatórios são sempre publicados no portal https://app.powerbi.com/home.

Portanto, você precisa ter uma conta e estar autorizado no Power BI Desktop. 

Para publicar, você precisa selecionar Publish e, se necessário, selecionar um espaço de trabalho.

Depois de publicar, visite o portal e encontre nosso relatório.

Um relatório desse tipo pode ser ajustado, mas está sujeito a restrições. Elas são principalmente relacionadas ao fato de que você não pode adicionar novas colunas ou medidas. No entanto, isso não impede você de adicionar visualizações com base nas colunas existentes. 

Esse relatório só está disponível para usuários do Power BI a que você deu acesso. Para compartilhar seu relatório com outras pessoas, você pode publicá-lo na Web ao selecionar Publish it to web (public). 

 

Atualização de dados

Como não configuramos o Gateway do Power BI, a atualização automática não está ativada. Você só pode atualizar os dados manualmente. Para fazer isso, você precisa abrir o relatório, clicar no botão Refresh e publicá-lo novamente.

Tableau

Preparação preliminar.

Você precisará de um driver para a conexão. Usamos Cloudera Hive. É possível baixar no site oficial (é necessário se inscrever). Você precisa conhecer o SO e a profundidade de bit para escolher a versão mais adequada para download. A instalação é simples (não exige explicação).

Conexão a cubos.

Para conectar um cubo a um relatório do Tableau, faça o download do arquivo de conexão. Para isso, selecione o projeto publicado desejado na página do projeto, acesse a guia de conexão e selecione a opção Tableau. 

Na janela exibida, selecione DOWNLOAD TDS

Ao iniciar o Tableau, no menu à esquerda, selecione Connect, To a File e More… na lista e abra o arquivo .tds baixado anteriormente.

O Tableau pedirá para você inserir seu nome de usuário e senha da AtScale. Após a autorização, seu cubo aparecerá nas origens de dados, permitindo que você comece a trabalhar.

Criando visualizações.

Ao contrário do Power BI, cada visual é criado em uma página separada. However, you can later group them on the worksheet. O Tableau tem linhas e colunas, mas a interface depende de onde as dimensões e medidas estão localizadas.

Para selecionar o tipo de visualização, você precisa clicar em "Show Me" (Me mostre) no canto superior direito da tela (quando você modifica o tipo de visualização, a localização dos valores selecionados pode mudar).

O campo para filtrar dados por padrão está localizado no cartão à esquerda.

 

Os valores podem ser filtrados manualmente, por curinga, condição ou top (bottom). Você também pode combinar esses tipos de filtros.

É possível alterar o formato de visualização em Marks.

Uma planilha é usada para o agrupamento. À esquerda, há uma lista com todas as planilhas disponíveis que podem ser arrastadas e agrupadas como você quiser. Além disso, em Worksheets no card Objects, você pode selecionar e adicionar texto, imagens etc. 

Publicando no servidor.

No Tableau, você pode publicar seus relatórios no Tableau Public, Tableau Online e Tableau Server. A funcionalidade dos dois últimos programas é idêntica. A única diferença é que o Tableau Online é mantido pelo próprio Tableau, enquanto o Tableau Server será mantido no lado da sua organização. Você pode publicar seus relatórios nele com uma conexão em tempo real, modificar relatórios publicados sem limitar a funcionalidade ou editar um relatório publicado no Tableau Desktop. A única desvantagem dos servidores é a impossibilidade de compartilhar seus relatórios com alguém que não está registrado no servidor. Em outras palavras, esses relatórios se destinam ao uso exclusivo na organização.O Tableau Public permite que você compartilhe seus relatórios com quem tem um link, mas não deixa você usar uma conexão de dados direta.

Vamos conectar ao Tableau Server.

Primeiro, precisamos fazer login.

Selecione o servidor desejado e passe pela autorização. Em seguida, selecione Publish Workbook (Publicar pasta de trabalho). 

Especifique os parâmetros necessários.Para uma visualização conveniente, recomendamos selecionarShow sheets as tabs (Mostrar planilhas como guias).

Se você quiser, é possível incorporar senhas. Caso contrário, você terá que especificar o login e a senha para nossa origem de dados sempre que entrar na sua conta. Você pode incorporar todas as senhas ao mesmo tempo clicando em Embed All Passwords.

Por fim, é hora de acessar o servidor, selecionar o item Explore e encontrar nossa pasta.


 

0
0 182
Artigo Danusa Calixto · Dez. 4, 2023 4m read

Olá, comunidade,

Neste artigo, listei 5 funções SQL úteis com explicações e exemplos de consultas👇🏻
Estas são as 5 funções:

  • COALESCE
  • RANK
  • DENSE_RANK
  • ROW_NUMBER
  • Função para obter totais correntes

Vamos começar com a função COALESCE

#COALESCE

A função COALESCE avalia uma lista de expressões na ordem da esquerda para a direita e retorna o valor da primeira expressão que não é NULL. Se todas as expressões forem avaliadas como NULL, é retornado NULL.

A declaração a seguir retorna o primeiro valor que não é nulo, ou seja, "intersystems"

SELECTCOALESCE(NULL, NULL, NULL,'intersystems', NULL,'sql')

Vamos criar a tabela abaixo como outro exemplo

CREATETABLE EXPENSES(
    TDATE     DATENOTNULL,
    EXPENSE1   NUMBERNULL,
    EXPENSE2   NUMBERNULL,
    EXPENSE3   NUMBERNULL,
    TTYPE  CHAR(30) NULL)

Agora vamos inserir alguns dados falsos para testar nossa função

 INSERTINTO sqluser.expenses (tdate, expense1,expense2,expense3,ttype )  
  SELECT {d'2023-01-01'}, 500,400,NULL,'Present'
  UNION ALL
  SELECT {d'2023-01-01'}, NULL,50,30,'SuperMarket'
  UNION ALL 
  SELECT {d'2023-01-01'}, NULL,NULL,30,'Clothes' 
  UNION ALL
  SELECT {d'2023-01-02'}, NULL,50,30 ,'Present'
  UNION ALL
  SELECT {d'2023-01-02'}, 300,500,NULL,'SuperMarket'
  UNION ALL 
  SELECT {d'2023-01-02'}, NULL,400,NULL,'Clothes'   
  UNION ALL
  SELECT {d'2023-01-03'}, NULL,NULL,350 ,'Present'
  UNION ALL
  SELECT {d'2023-01-03'}, 500,NULL,NULL,'SuperMarket'
  UNION ALL 
  SELECT {d'2023-01-04'}, 200,100,NULL,'Clothes'
  UNION ALL
  SELECT {d'2023-01-06'}, NULL,NULL,100,'SuperMarket'
  UNION ALL 
  SELECT {d'2023-01-06'}, NULL,100,NULL,'Clothes'  

Selecione os dados

Agora, usando a função COALESCE, vamos recuperar o primeiro valor que não é NULL nas colunas expense1, expense2 e expense3

SELECT TDATE,
COALESCE(EXPENSE1,EXPENSE2,EXPENSE3),
TTYPE
FROM sqluser.expenses ORDERBY2   

Funções #RANK x DENSE_RANK x ROW_NUMBER

  • RANK()— atribui um número inteiro de classificação a cada coluna no mesmo frame de janela, começando em 1. Os números inteiros de classificação podem incluir valores duplicados se várias linhas tiverem o mesmo valor para o campo de função da janela.
  • ROW_NUMBER() — atribui um número inteiro sequencial exclusivo a cada linha no mesmo frame de janela, começando em 1. Se várias linhas tiverem o mesmo valor para o campo de função da janela, cada linha receberá um número inteiro sequencial único.
  • DENSE_RANK() não deixa lacunas após uma classificação duplicada.

No SQL, há várias maneiras de atribuir uma classificação a uma linha, que vamos analisar com um exemplo. Considere novamente o mesmo exemplo acima, mas agora queremos saber quais são as despesas mais altas.

Queremos saber onde eu gasto mais dinheiro. Há diferentes maneiras de fazer isso. Podemos usar todas as ROW_NUMBER() , RANK() e DENSE_RANK() . Vamos ordenar a tabela anterior usando todas as três funções e ver quais são as principais diferenças entre elas usando a seguinte consulta:

Confira nossa consulta abaixo:

A principal diferença entre as três funções é a forma como lidamos com os vínculos. Vamos analisar mais a fundo as diferenças:

  • ROW_NUMBER()retorna um número único para cada linha começando em 1. Quando há vínculos, ele atribui arbitrariamente um número se o segundo critério não estiver definido.
  • RANK()retorna um número único para cada linha começando em 1, exceto quando há vínculos, porque ele atribui o mesmo número. Além disso, uma lacuna segue a classificação duplicada.
  • DENSE_RANK() não deixa lacunas depois de uma classificação duplicada.

#Calculando totais correntes

O total corrente é provavelmente uma das funções de janela mais úteis, principalmente quando você quer visualizar o crescimento. Usando uma função de janela com SUM(), podemos calcular uma agregação cumulativa.

Para fazer isso, só precisamos somar uma variável usando o agregador SUM() , mas ordenar essa função usando uma coluna TDATE. 

É possível observar esta consulta correspondente:

Como você pode observar na tabela acima, agora temos a agregação acumulada da quantidade de dinheiro gasto conforme passam as datas.

Conclusão

O SQL é ótimo. As funções usadas acima podem ser úteis ao lidar com análise de dados, ciência de dados e qualquer outro campo relacionado a dados.

Por isso, você deve continuar a melhorar suas habilidades de SQL.


Obrigado

0
0 180
Artigo Danusa Calixto · Dez. 4, 2023 14m read

Com frequência, me pedem para avaliar dados de desempenho relacionados a aplicativos IRIS de clientes para entender se os recursos do sistema são sub ou superprovisionados.

Este exemplo recente é interessante, porque envolve um aplicativo que fez uma migração "lift and shift" de um grande aplicativo de banco de dados IRIS para a nuvem. AWS, no caso.

Um aprendizado importante é que, depois de migrar para a nuvem, os recursos podem ser dimensionados corretamente ao longo do tempo conforme necessário. Não é preciso comprar e provisionar infraestrutura local para o crescimento que você espera alcançar daqui a vários anos no futuro.

É necessário monitoramento contínuo. A taxa de transações do seu aplicativo mudará à medida que seu negócio e o próprio aplicativo ou o uso dele mudar. Isso alterará os requisitos de recursos do sistema. Planejadores também devem considerar picos sazonais na atividade. Claro, uma vantagem da nuvem é que os recursos podem ser aumentados ou reduzidos conforme necessário.

Para mais informações contextuais, há vários posts detalhados sobre AWS e IRIS na comunidade. Um bom ponto de partida é pesquisar "referência da AWS". Também adicionei alguns links úteis no final deste post.

Os serviços da AWS são como blocos de Lego: tamanhos e formatos diferentes podem ser combinados. Ignorei networking, segurança e preparação de uma VPC para este post. Foquei em dois dos componentes de blocos de Lego;

  • Requisitos de computação.
  • Requisitos de armazenamento.

Visão geral

O aplicativo é um sistema de informações de saúde usado em um grupo de hospitais movimentados. Os componentes da arquitetura em que estou focando aqui incluem dois servidores de bancos de dados em um cluster de tolerância a falhas de espelho da InterSystems.

Barra lateral: os espelhos estão em zonas de disponibilidade separadas para alta disponibilidade adicional.


Requisitos de computação

Tipos de instância EC2

O Amazon EC2 oferece uma ampla seleção de tipos de instância otimizados para diferentes casos de uso. Os tipos de instância compreendem combinações FIXAS variadas de CPU e memória, além de limites máximos fixos de capacidade de armazenamento e de networking. Cada tipo de instância inclui um ou mais tamanhos de instância.

Os atributos da instância EC2 que devem ser analisados com mais atenção incluem:

  • Núcleos de vCPU e memória.
  • Máximo de IOPS e taxa de transferência de IO.

Para aplicativos IRIS como esse com um grande servidor de banco de dados, dois tipos de instâncias EC2 são apropriadas: 

  • EC2 R5 e R6i estão na família de instâncias com memória otimizada e são adequadas para cargas de trabalho com uso intensivo da memória, como IRIS. Há 8 GB de memória por vCPU.
  • EC2 M5 e M6i estão na família de instâncias de uso geral. Há 4 GB de memória por vCPU. Elas são mais usadas para servidores da Web, de impressão e de não produção.

Observação: nem todos os tipos de instâncias estão disponíveis em todas as regiões da AWS. As instâncias R5 foram usadas nesse caso porque a R6i lançada mais recentemente não estava disponível.

Planejamento de capacidade

Quando um sistema local existente está disponível, o planejamento da capacidade significa medir o uso atual de recursos, traduzindo isso para os recursos na nuvem pública e adicionando recursos para o crescimento previsto a curto prazo. Geralmente, se não há outros limites de recursos, os aplicativos do banco de dados do IRIS são escalados linearmente nos mesmos processadores. Por exemplo, imagine adicionar um novo hospital ao grupo. O aumento do uso do sistema (taxa de transações) em 20% exigiria 20% mais recursos de vCPU usando os mesmos tipos de processadores. É claro que isso não é garantido. Valide seus aplicativos.

Requisitos de vCPU

Antes da migração, a utilização da CPU chegava a quase 100% em períodos movimentados. O servidor no local tem 26 vCPUs. Uma boa regra geral é avaliar sistemas com um pico esperado de 80% de utilização da CPU. Isso permite picos temporários na atividade ou outras atividades incomuns. Confira abaixo um gráfico de exemplo para a utilização da CPU em um dia típico.

image

O monitoramento dos servidores locais exigiria o aumento para 30 núcleos de vCPUs, trazendo o pico geral de utilização para abaixo de 80%. O cliente esperava adicionar um crescimento de transações de 20% no curto prazo. Então, um buffer de 20% é adicionado aos cálculos, permitindo também uma capacidade de reserva adicional para o período de migração.

Um cálculo simples é que 30 núcleos + 20% de crescimento e buffer de migração equivale a 36 núcleos de vCPU necessários

Dimensionamento para a nuvem

Lembre-se de que as instâncias EC2 da AWS em cada tipo de família têm tamanhos fixos de vCPU e memória e definem limites máximos de IOPS, armazenamento e taxa de transferência de rede.

Por exemplo, os tipos de instância disponíveis nas famílias R5 e R6i incluem:

  • 16 vCPUs e memória de 128 GB
  • 32 vCPUs e memória de 256 GB
  • 48 vCPUs e memória de 384 GB
  • 64 vCPUs e memória de 512 GB
  • E assim por diante.

Regra geral: Uma maneira simplificada de dimensionar uma instância EC2 a partir de métricas locais conhecidas para a nuvem é arredondar os requisitos de vCPU locais recomendados para o próximo tamanho de instância EC2 disponível.

Ressalvas: Pode haver várias outras considerações. Por exemplo, diferenças nos tipos e nas velocidades dos processadores locais e do EC2, ou um armazenamento mais eficiente na nuvem do que em um sistema local antigo, podem significar que os requisitos de vCPU mudam. Por exemplo, é possível ter mais IO e fazer mais trabalho em menos tempo, aumentando o pico de utilização da vCPU. Os servidores locais podem ter um processador de CPU completo, incluindo hyper-threading, e as vCPUs das instâncias na nuvem serem um único hyper thread. Por outro lado, as instâncias EC2 são otimizadas para transferir parte do processamento para placas Nitro integradas. Assim, os principais núcleos de vCPU gastam mais ciclos processando as cargas de trabalho, melhorando o desempenho das instâncias. Porém, em resumo, a regra acima é um ótimo guia para começar. A vantagem da nuvem é que, com monitoramento contínuo, você pode planejar e mudar o tipo de instância para otimizar o desempenho e custo.

Por exemplo, para traduzir 30 ou 36 vCPUs locais em tipos de instância EC2 semelhantes:

  • O r5.8xlarge tem 32 vCPUs, 256 GB de memória e um máximo de 30.000 IOPS.
  • O r512xlarge tem 48 vCPUs, 384 GB de memória e um máximo de 40.000 IOPS

Observe o máximo de IOPS. Isso será importante mais tarde.

Resultados

Uma instância r512xlarge foi selecionada para os espelhos do banco de dados do IRIS para a migração.

Nas semanas seguintes à migração, o monitoramento mostrou que o tipo de instância de 48 vCPUs sustentou picos de quase 100% de utilização da vCPU. No entanto, em geral, o processamento chegou a aproximadamente 70%. Isso está bem dentro da faixa aceitável e, se os períodos de alta utilização forem atribuídos a um processo que pode ser otimizado, há bastante capacidade de reserva para considerar o dimensionamento para uma especificação inferior e um tipo de instância EC2 mais barato.

image

Um tempo depois, o tipo de instância permaneceu igual. Uma verificação do desempenho do sistema mostra que o pico de utilização da vCPU caiu para cerca de 50%. No entanto, ainda há picos temporários perto de 100%.

image

Recomendação

É necessário monitoramento contínuo. Com o monitoramento constante, o sistema pode ser dimensionado corretamente para alcançar o desempenho necessário e ter uma execução mais barata.

Os picos temporários na utilização da vCPU devem ser investigados. Por exemplo, um relatório ou uma tarefa em lote podem ser retirados do horário comercial, diminuindo o pico geral da vCPU e reduzindo qualquer impacto negativo nos usuários interativos do aplicativo.

Revise os requisitos de IOPS e taxa de transferência de armazenamento antes de mudar o tipo de instância. Não se esqueça que os tipos de instância têm limites máximos fixos de IOPS.

As instâncias podem ser dimensionadas usando o espelhamento de tolerância a falhas. Etapas simplificadas:

  • Desligue o espelho de backup.
  • Ligue o espelho de backup usando uma instância menor ou maior com configurações alteradas para montar o armazenamento do EBS e contar com uma menor pegada de memória (considere, por exemplo, hugepages do Linux e buffers globais do IRIS).
  • Aguarde a atualização do espelho de backup.
  • Aplique a tolerância a falhas ao espelho de backup para que se torne principal.
  • Repita, redimensione o espelho restante, coloque-o online novamente e atualize.

Observação: durante a tolerância a falhas do espelho, haverá uma breve interrupção para todos os usuários, interfaces etc. No entanto, se forem usados servidores de aplicações ECP, poderá não haver nenhuma interrupção para os usuários. Os servidores de aplicações também podem fazer parte de uma solução de escalonamento automático.

Outras opções econômicas incluem executar o espelho de backup em uma instância menor. No entanto, há um risco significativo de desempenho reduzido (e usuários insatisfeitos) se uma tolerância a falhas ocorrer em momentos de pico de processamento.

Ressalvas: As vCPUs e memória das instâncias são fixas. Recomeçar com uma instância e pegada de memória menores implica em um cache de buffer global menor, o que pode aumentar a taxa de IOPS de leitura do banco de dados. Considere os requisitos de armazenamento antes de reduzir o tamanho da instância. Automatize e teste o dimensionamento para minimizar o risco de erro humano, especialmente se for uma ocorrência comum.


Requisitos de armazenamento

Um desempenho de IO de armazenamento previsível com baixa latência é essencial para fornecer escalabilidade e confiabilidade para seus aplicativos.

Tipos de armazenamento

O armazenamento do Amazon Elastic Block Store (EBS) é recomendado para a maioria dos aplicativos de banco de dados do IRIS com altas taxas de transações. O EBS oferece vários tipos de volumes que permitem otimizar o desempenho do armazenamento e o custo para uma ampla variedade de aplicativos. O armazenamento baseado em SSD é necessário para cargas de trabalho transacionais, como aplicativos que usam bancos de dados do IRIS.

Dos tipos de armazenamento SSD, os volumes gp3 são geralmente recomendados para bancos de dados do IRIS, porque equilibram o preço e o desempenho para aplicativos transacionais. No entanto, para casos excepcionais com taxas muito altas de IOPS ou de transferência, o io2 pode ser usado (geralmente por um custo mais alto). Há outras opções, como as soluções de armazenamento temporário anexado localmente e arrays virtuais de terceiros. Se você tiver requisitos que ultrapassam as capacidades do io2, fale com a InterSystems sobre suas necessidades.

O armazenamento acompanha limites e custos, por exemplo.

  • Os volumes gp3 oferecem uma linha de base de medição de desempenho de 3.000 IOPS e 125 MiBps em qualquer tamanho de volume, com uma latência de milissegundos de um dígito 99% do tempo para o custo base da capacidade de GB de armazenamento. Os volumes gp3 podem ser escalonados para 16.000 IOPS e 1.000 MiBps de taxa de transferência por um custo adicional. O armazenamento é precificado por GB e com base no provisionamento de IOPS acima da linha de base de 3.000 IOPS.
  • Os volumes io2 oferecem uma linha de base de medição de desempenho constante de até 500 IOPS/GB para um máximo de 64.000 IOPS com uma latência de milissegundos de um dígito 99% do tempo. O armazenamento é precificado por GB e com base no provisionamento de IOPS.

Lembre-se: as instâncias EC2 também têm limites de IOPS e taxa de transferência total do EBS. Por exemplo, o r5.8xlarge tem 32 vCPUs e um máximo de 30.000 IOPS. Nem todos os tipos de instâncias são otimizados para usar os volumes do EBS.

Planejamento de capacidade

Quando um sistema local existente está disponível, o planejamento da capacidade significa medir o uso atual de recursos, traduzindo isso para os recursos na nuvem pública e adicionando recursos para o crescimento previsto a curto prazo.

Os dois recursos essenciais que devem ser considerados:

  • Capacidade de armazenamento. Quantos GB de armazenamento de banco de dados são necessários e qual é o crescimento esperado? Por exemplo, você sabe o crescimento médio histórico de banco de dados do seu sistema local para uma taxa de transações conhecida. Nesse caso, você pode calcular os tamanhos de banco de dados futuros com base em qualquer crescimento previsto da taxa de transações. Você também precisará considerar outros tipos de armazenamento, como diários.
  • IOPS e taxa de transferência. Esse é o mais interessante e é abordado em detalhes abaixo.

Requisitos de banco de dados

Antes da migração, as leituras de disco de banco de dados atingiam cerca de 8.000 IOPS.

image

A taxa de IOPS de leitura e escrita ultrapassava 40.000 em alguns dias. Embora, durante o horário comercial, os picos sejam bem mais baixos.

image

A taxa de transferência total de leituras e escritas atingiu cerca de 600 MB/s.

image

Lembre-se: as instâncias EC2 e os volumes do EBS têm limites de IOPS E taxa de transferência*. O limite que for atingido primeiro resultará na restrição desse recurso pela AWS, causando a degradação do desempenho e possivelmente afetando os usuários do seu sistema. Você precisa provisionar IOPS E taxa de transferência.

Dimensionamento para a nuvem

Os volumes gp3 são usados para equilibrar o preço e o desempenho. No entanto, nesse caso, o limite de 16.000 IOPS para um único volume gp3 foi excedido, e há a expectativa de que os requisitos aumentarão no futuro.

Para permitir o provisionamento de uma taxa IOPS mais alta do que o possível em um único volume gp3, é usada uma distribuição do LVM.

Para a migração, o banco de dados é implantado usando uma distribuição do LVM de quatro volumes gp3 com o seguinte:

  • 8.000 IOPS provisionadas em cada volume (para um total de 32.000 IOPS).
  • Taxa de transferência de 250 MB/s provisionada em cada volume (para um total de 1.000 MB/s).

O processo exato de planejamento de capacidade foi realizado para o Write Image Journal (WIJ) e os discos locais de diário de transações. O WIJ e os discos de diário foram provisionados em um único disco gp3 cada.

Para mais detalhes e um exemplo de como usar uma distribuição do LVM, veja: https://community.intersystems.com/post/using-lvm-stripe-increase-aws-ebs-iops-and-throughput

Regra geral: Se os seus requisitos ultrapassarem os limites de um único volume gp3, investigue a diferença de custo entre usar IOPS provisionadas do gp3 do LVM e do io2.

Ressalvas: Garanta que a instância EC2 não limite as taxas de IOPS ou de transferência.

Resultados

Nas semanas seguintes à migração, as IOPS de escrita de banco de dados atingiram cerca de 40.000 IOPS, semelhante a no local. No entanto, as IOPS de leitura de banco de dados foram muito mais baixas.

Uma menor taxa de IOPS de leitura é esperada devido à instância EC2 ter mais memória disponível para armazenar dados em cache nos buffers globais. Mais dados do conjunto de trabalho do aplicativo na memória significa que eles não precisam ser chamados de um armazenamento SSD muito mais lento. Lembre-se, acontecerá o oposto se você reduzir a pegada de memória.

image

Durante os momentos de pico de processamento, o volume do banco de dados teve picos de latência acima de 1 ms. No entanto, os picos são temporários e não afetam a experiência do usuário. O desempenho do armazenamento é excelente.

image

Depois, uma verificação de desempenho do sistema mostra que, embora haja alguns picos, geralmente, a taxa de IOPS de leitura ainda é menor do que no local.

image

Recomendação

É necessário monitoramento contínuo. Com o monitoramento constante, o sistema pode ser dimensionado corretamente para alcançar o desempenho necessário e ter uma execução mais barata.

O processo de aplicação responsável pelos 20 minutos de alta IOPS de escrita de banco de dados durante a noite (gráfico não exibido) deve ser analisado para entender o que ele está fazendo. As escritas não são afetadas por grandes buffers globais e ainda estão na faixa de 30-40.000 IOPS. O processo poderia ser concluído com um menor provisionamento de IOPS. No entanto, haverá um impacto mensurável na latência de leitura do banco de dados se as escritas sobrecarregarem o caminho de IO, afetando negativamente os usuários interativos. A latência de leitura precisa ser monitorada atentamente se as leituras forem limitadas por um longo período.

O provisionamento de IOPS e taxa de transferência de disco do banco de dados pode ser ajustado pelas APIs da AWS ou interativamente pelo console da AWS. Como quatro volumes do EBS compõem o disco LVM, os atributos de IOPS e de taxa de transferência dos volumes do EBS precisam ser ajustados igualmente.

O WIJ e o diário também devem ser monitorados continuamente para entender se é possível fazer alguma alteração no provisionamento de IOPS e de taxa de transferência.

Observação: o volume do WIJ tem requisitos de alta taxa de transferência (não IOPS) devido ao tamanho do bloco de 256 kB. A taxa de IOPS do volume do WIJ pode estar abaixo da linha de base de 3.000 IOPS, mas a taxa de transferência está atualmente acima da linha de base de taxa de transferência de 125 MB/s. É provisionada uma taxa de transferência adicional no volume do WIJ.

Ressalvas: Diminuir o provisionamento de IOPS para limitar o período de altas escritas noturnas resultará em um ciclo mais longo do daemon de escrita (WIJ mais escritas aleatórias de banco de dados). Isso pode ser aceitável se as escritas forem concluídas em 30-40 segundos. No entanto, pode haver um grave impacto na latência de leitura e IOPS de leitura e, portanto, na experiência dos usuários interativos no sistema por 20 minutos ou mais. Prossiga com cautela.


Links úteis

AWS


0
0 119
Artigo Danusa Calixto · Nov. 27, 2023 6m read

Olá, comunidade!

Acho que todo mundo deixa o código-fonte do projeto no repositório hoje em dia: Github, GitLab, bitbucket, etc. A mesma coisa para projetos do InterSystems IRIS , confira qualquer um no Open Exchange.

O que fazemos sempre que começamos ou continuamos a trabalhar com um determinado repositório usando a Plataformas de Dados InterSystems?

Precisamos de uma máquina do InterSystems IRIS local, bem como configurar o ambiente para o projeto e importar o código-fonte.

Portanto, todo desenvolvedor faz o seguinte:

  1. Verifica o código no repositório
  2. Instala/executa a instalação do IRIS local
  3. Cria um novo namespace/banco de dados para um projeto
  4. Importa o código nesse novo namespace
  5. Configura todo o ambiente rest
  6. Começa/continua a programar o projeto 

Se você "dockerizar" seu repositório, as linhas de etapas podem ser resumidas em 3 etapas:

  1. Verifica o código no repositório
  2. Executa o docker-compose build 
  3. Começa/continua a programar o projeto 

Aproveite - nada do trabalho manual das etapas 3, 4 e 5, que podem levar minutos e trazer dor de cabeça às vezes.

Você pode "dockerizar" (quase) qualquer repositório da InterSystems seguindo algumas etapas. Vamos lá!

Como "dockerizar" o repositório e o que isso significa? 

Basicamente, a ideia é ter o docker instalado na máquina que compilará o código e o ambiente em um contêiner, que será executado no docker e funcionará da maneira apresentada em primeiro lugar pelo desenvolvedor. Sem "Qual é a versão do SO?" e "O que mais você tinha nessa instalação do IRIS?".

É sempre uma página limpa (ou um contêiner IRIS limpo) que usamos para configurar o ambiente (namespaces, bancos de dados, web apps, usuários/funções) e importar o código em um banco de dados limpo recém-criado.

Esse procedimento de "dockerizar" prejudicará muito seu repositório atual? 

Não. Ele precisará adicionar 2 ou 3 novos arquivos na raiz do repositório e seguir algumas regras que você pode configurar por conta própria.

Pré-requisitos

Baixar e instalar o docker.

Baixar e instalar a imagem do docker IRIS. Neste exemplo, usarei a prévia completa do InterSystems IRIS:  iris:2019.1.0S.111.0, que você pode baixar na prévia da WRC. Veja os detalhes.

Se você trabalha com a instância que precisa de uma chave, coloque a iris.key no local que você a usará o tempo todo. Coloquei no diretório de usuário do meu Mac.

"Dockerizando" o repositório

Para "dockerizar" seu repositório, você precisa adicionar três arquivos na pasta raiz dele.

Aqui está o exemplo de repositório dockerizadodo projeto - ISC-DEV, que ajuda a importar/exportar o código-fonte do banco de dados IRIS.  Esse repositório tem Dockerfile, docker-compose.yml e installer.cls adicionais que vou descrever abaixo.

Primeiro, há um Dockerfile, que será usado pelo comando docker-compose build

 
Dockerfile
FROM intersystems/iris:2019.1.0S.111.0 # precisa ser a mesma imagem instalada 

WORKDIR /opt/app

COPY ./Installer.cls ./

COPY ./cls/ ./src/

RUN iris start $ISC_PACKAGE_INSTANCENAME quietly EmergencyId=sys,sys && \

    /bin/echo -e "sys\nsys\n" \

            # dando %ALL ao usuário administrador

            " Do ##class(Security.Users).UnExpireUserPasswords(\"*\")\n" \

            " Do ##class(Security.Users).AddRoles(\"admin\", \"%ALL\")\n" \

            # importando e executando o instalador

            " Do \$system.OBJ.Load(\"/opt/app/Installer.cls\",\"ck\")\n" \

            " Set sc = ##class(App.Installer).setup(, 3)\n" \

            " If 'sc do \$zu(4, \$JOB, 1)\n" \

            # apresentando a autorização no nível do SO (para remover o prompt de login/senha do contêiner)

            " Do ##class(Security.System).Get(,.p)\n" \

            " Set p(\"AutheEnabled\")=p(\"AutheEnabled\")+16\n" \

            " Do ##class(Security.System).Modify(,.p)\n" \

            " halt" \

    | iris session $ISC_PACKAGE_INSTANCENAME && \

    /bin/echo -e "sys\nsys\n" \

    | iris stop $ISC_PACKAGE_INSTANCENAME quietly

CMD [ "-l", "/usr/irissys/mgr/messages.log" ]

 

Esse Dockerfile copia o installer.cls e o código-fonte da pasta /cls do repositório para a pasta /src e para o contêiner

Ele também executa algumas configurações, dando ao usuário administrador a função %All e a senha infinita ‘SYS’, apresenta a autorização no nível do SO e executa o %Installer. 

O que está no %Installer?

Class App.Installer

{

XData MyInstall [ XMLNamespace = INSTALLER ]

{

<Manifest>

  <Default Name="NAMESPACE" Value="ISCDEV"/>

  <Default Name="DBNAME" Value="ISCDEV"/>

  <Default Name="APPPATH" Dir="/opt/app/" />

  <Default Name="SOURCESPATH" Dir="${APPPATH}src" />

  <Default Name="RESOURCE" Value="%DB_${DBNAME}" /> 

  <Namespace Name="${NAMESPACE}" Code="${DBNAME}-CODE" Data="${DBNAME}-DATA" Create="yes" Ensemble="0">

    <Configuration>

      <Database Name="${DBNAME}-CODE" Dir="${APPPATH}${DBNAME}-CODE" Create="yes" Resource="${RESOURCE}"/>

      <Database Name="${DBNAME}-DATA" Dir="${APPPATH}${DBNAME}-DATA" Create="yes" Resource="${RESOURCE}"/>

    </Configuration>

    <Import File="${SOURCESPATH}" Recurse="1"/>

  </Namespace>

</Manifest>

}

ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]

{

  Return ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "MyInstall")

}

}

Isso cria o namespace/banco de dados ISCDEV e importa o código da pasta de origem -/src.

Em seguida, há o arquivo docker-compose.yml, que será usado ao executar o contêiner com o comando docker-compose up.

version: '2.4'

services:

iris:

build: .

restart: always

ports:

  - 52773:52773

volumes:

  - ~/iris.key:/usr/irissys/mgr/iris.key</pre>

 

Essa config dirá ao docker em qual porta vamos esperar que o IRIS trabalhe em nosso host. O primeiro (52773) é um host, o segundo é uma porta interna de um contêiner (52773)

na seção "volumes", o docker-compose.yml fornece acesso a uma chave iris na sua máquina dentro do contêiner  no local em que o IRIS está procurando por ela:

- ~/iris.key:/usr/irissys/mgr/iris.key

Para começar a programar com esse repositório, faça o seguinte:

1. Faça o clone/git pull do repositório em qualquer diretório local.

 2. Abra o terminal nesse diretório e execute

user# docker-compose build

isso criará o contêiner.

3. Execute o contêiner IRIS com seu projeto

user# docker-compose up -d

Abra seu IDE favorito, conecte ao servidor em localhost://52773 e desenvolva seu sucesso com as Plataformas de Dados do InterSystems IRIS ;)

Você pode usar esses 3 arquivos para "dockerizar" seu repositório. Basta colocar o nome correto para o código-fonte no Dockerfile, o(s) namespace(s) correto(s) no Installer.cls e um local para a iris.key no docker-compose.yml para aproveitar os benefícios dos contêineres do Docker no seu desenvolvimento diário do InterSystems IRIS.

0
0 119
Artigo Danusa Calixto · Nov. 19, 2022 20m read

Criado por Daniel Kutac, Engenheiro de vendas, InterSystems

Aviso: se você ficar confuso com os URLs usados: a série original usou telas de uma máquina chamada dk-gs2016. As novas capturas de tela foram tiradas em uma máquina diferente. Você pode tratar o URL WIN-U9J96QBJSAG como se fosse o dk-gs2016 com segurança.

Parte 2. Servidor de autorização, servidor OpenID Connect

Na parte anterior desta série curta, aprendemos sobre o caso de uso simples – atuando como um cliente OAUTH[1]. Agora, é hora de levar nossa experiência a um nível completamente novo. Vamos construir um ambiente muito mais complexo, onde o InterSystems IRIS vai desempenhar todas as funções OAUTH.

Já sabemos como fazer um cliente, então vamos nos concentrar no servidor de autorização e, ainda mais, no provedor OpenID Connect[2].

Como na parte anterior, precisamos preparar o ambiente. Desta vez, será mais complicado, pois há mais partes móveis.

Antes de entrarmos nos detalhes do nosso exemplo, precisamos falar algumas palavras sobre o OpenID Connect.

Como você deve lembrar, na parte anterior, recebemos a solicitação – para ter a autorização do Google – para nos autenticarmos primeiro com o Google. A autenticação não faz parte do framework OAUTH. Na verdade, há vários frameworks de autenticação, independentes do OAUTH. Um deles é chamado OpenID. Originalmente uma iniciativa independente, ele agora aproveita a infraestrutura fornecida pelo framework OAUTH, ou seja, as estruturas de comunicação e dados. Assim, nasceu o OpenID Connect. Na verdade, muitas pessoas o chamam de OAUTH em esteroides. De fato, com o OpenID Connect, você pode não só autorizar, mas também autenticar usando interfaces bem conhecidas do framework OAUTH.

Demonstração complexa do OpenID Connect

Aproveitaremos grande parte do código do cliente da parte 1. Isso nos poupa muito trabalho, para que possamos nos concentrar na configuração do ambiente.

Pré-requisitos

Desta vez, precisamos adicionar uma infraestrutura PKI ao servidor web já existente com SSL habilitado. Precisamos de criptografia exigida pelo OpenID Connect. Se você quer autenticar alguém, precisa ter certeza absoluta de que ninguém mais pode se passar pelo agente (cliente, servidor de autenticação...) que envia os dados confidenciais pela rede. É aqui que entra a criptografia baseada em X.509.

Observação: a partir do Cache 2017.1, não é mais necessário usar certificados X.509 para gerar JWT/JWKS (JSON Web Key Set). Devido à compatibilidade com versões anteriores e simplicidade, usamos essa opção.

PKI

A rigor, não precisamos usar a infraestrutura Caché PKI, mas é mais conveniente do que usar ferramentas como openssl diretamente para gerar todos os certificados.

Não entraremos em detalhes sobre a geração de certificados aqui, pois você pode encontrá-los na documentação do InterSystems IRIS. Como resultado da geração de certificados, criaremos 3 pares de chaves públicas/privadas e certificados associados.

Vamos chamá-los de

·        root_ca (root_ca.cer) para nossa autoridade de certificação emissora

·        auth (auth.cer e auth.key) para o servidor de autorização e OpenID

·        client (client.cer e client.key) para o servidor de aplicação do cliente

Credenciais X.509

Precisamos definir credenciais X.509 em servidores individuais para que eles possam assinar e validar JSON Web Tokens (JWT) trocados durante nossa demonstração

Configuração do servidor de autenticação e autorização

Sem entrar em detalhes sobre como definir credenciais X.509, apenas mostramos uma captura de tela das credenciais da instância AUTHSERVER.

Como a imagem indica, o AUTHSERVER possui a própria chave privada e o certificado, enquanto só possui o certificado com a chave pública de CLIENT

Configuração do servidor cliente

Da mesma forma, as credenciais definidas na instância CLIENT

Aqui o CLIENTE possui a chave privada e o certificado, mas somente o certificado com chave pública de AUTHSERVER.

Configuração do servidor de recursos

Não precisamos definir credenciais X509 na instância RESSERVER em nossa configuração de exemplo.

Configuração do OAUTH

Como a configuração descrita na parte 1 desta série, precisamos configurar nossos servidores para OAUTH. Vamos começar com a instância AUTHSERVER, pois é o componente central na configuração geral do OAUTH.

AUTHSERVER

No Portal de Gerenciamento de Sistemas, acesse System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Server Configuration (Configuração do Servidor).

Clique no link do menu e preencha os itens do formulário:

·        nome do host

·        porta (opcional)

·        prefixo (opcional) – esses três campos compõem o Issuer endpoint (endpoint do emissor)

·        especifique as condições para retornar o token de atualização

·        verifique os tipos de concessão compatíveis, para nossa demonstração basta verificar todos os quatro tipos. No entanto, apenas o código de autorização é usado.

·        opcionalmente, confira o público-alvo necessário – isso adiciona a propriedade aud no código de autorização e solicitações implícitas

·        opcionalmente, confira a sessão de usuário de suporte - isso significa que o cookie httpOnly é usado pelo servidor de autorização para manter o usuário atual deste navegador conectado.  A segunda solicitação e as solicitações subsequentes do token de acesso não pedirão o nome de usuário e a senha.

·        especifique os intervalos de endpoint

·        defina os escopos compatíveis com esse servidor

·        aceite o padrão ou insira valores de opções de personalização – observação: altere o valor da classe de token Generate de %OAuth2.Server.Generate para %OAuth2.Server.JWT para que um JWT seja usado como token de acesso em vez de um token opaco.

·        forneça o nome da configuração SSL registrada para estabelecer o SSL sobre o HTTP conforme exigido pelo OAuth 2.0

·        Preencha as configurações do JSON Web Token (JWT) 

Veja esta captura de tela da configuração de exemplo

Após definir a configuração do servidor, precisamos fornecer a configuração do cliente do servidor. Na página com o formulário de configuração do servidor, clique no botão Client Configurations e pressione Create New Configuration for your CLIENT and RESSERVER instances (Criar nova configuração para as instâncias CLIENT e RESSERVER).

Esta imagem mostra a configuração do CLIENT.

Deixe a guia JWT Token vazia — com valores padrão. Como você pode ver, nós preenchemos os campos com dados sem sentido, diferente de um caso de aplicação real.

Da mesma forma, a configuração do RESSERVER

Como você pode ver, há apenas informações muito básicas necessárias para o servidor de recursos, ou seja, você precisa definir o tipo de cliente para o servidor de recursos. Com CLIENT, você precisa fornecer mais informações, o tipo de cliente (confidencial, pois nosso cliente é executado como um web app capaz de manter o cliente em segredo no servidor, e não enviar para o agente cliente).

CLIENT

No SMP, acesse System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Client Configurations (Configurações do cliente).

Clique no botão Create Server Configuration (Criar configuração de servidor), preencha o formulário e salve.

Confira se o endpoint do emissor corresponde ao valor que definimos anteriormente na instância AUTHSERVER! Você também precisa modificar os endpoints do servidor de autorização de acordo com a configuração do seu servidor web. No nosso caso, apenas incorporamos 'authserver' em cada campo de entrada.

Agora, clique no link Client Configurations (Configurações do cliente) ao lado do Issuer Endpoint (Endpoint emissor) recém-criado e clique no botão Create Client Configuration (Criar configuração de cliente).

Ótimo! Agora, temos CLIENT e AUTHSERVER configurados. Isso pode ser suficiente para muitos casos de uso, pois o servidor de recursos pode ser apenas um namespace de AUTHSERVER, já protegido. Porém, vamos considerar que queremos cobrir um caso de uso em que um médico externo está tentando recuperar dados do nosso sistema clínico interno. Portanto, para permitir que esse médico recupere os dados, queremos armazenar as informações da conta dele DENTRO do nosso servidor de recursos para auditorias e fins forenses. Nesse caso, precisamos continuar e definir as configurações em RESSERVER.

RESSERVER

No SMP, acesse System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Client Configurations (Configurações do cliente).

Clique no botão Create Server Configuration (Criar configuração de servidor), preencha o formulário e salve.

Usamos a função de descoberta, um novo recurso implementado no Cache 2017.1

Como você pode ver, essa configuração está usando os mesmos dados que a configuração correspondente na instância CLIENT.

Agora, clique no link Client Configurations (Configurações do cliente) ao lado do Issuer Endpoint (Endpoint emissor) recém-criado e clique no botão Create Client Configuration (Criar configuração de cliente).

A criação do WT a partir das credenciais X.509 não é recomendada, mas nós as usamos para a compatibilidade.

Isso! Foi um processo tedioso, mas necessário. Agora, podemos avançar e começar a programar!

Aplicativo cliente

Para manter as coisas o mais simples possível, reciclaremos grande parte do código do nosso exemplo do Google que descrevemos na parte 1.

O aplicativo cliente tem apenas duas páginas de CSP, sendo executado no aplicativo /csp/myclient, sem segurança aplicada – ele é apenas executado como usuário não autenticado.

Página 1

Class Web.OAUTH2.Cache1N Extends %CSP.Page
{

Parameter OAUTH2CLIENTREDIRECTURI = "https://dk-gs2016/client/csp/myclient/Web.OAUTH2.Cache2N.cls";

Parameter OAUTH2APPNAME = "demo client";

ClassMethod OnPage() As %Status
{
  &html<<html>

<body>
  <h1>Authenticating and Authorizing against Cache&acute; OAuth2 provider</h1>
  <p>This page demo shows how to call Cache&acute; API functions using OAuth2 authorization.
  <p>We are going to call Cache&acute; authentication and authorization server to grant our application access to data stored at another
  Cache&acute; server.
 >

  // Get the url for authorization endpoint with appropriate redirect and scopes.
  // The returned url is used in the button below.

  // DK: use 'dankut' account to authenticate!
  set scope="openid profile scope1 scope2"
  set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(
    ..#OAUTH2APPNAME,
    scope,
    ..#OAUTH2CLIENTREDIRECTURI,
    .properties,
    .isAuthorized,
    .sc)
  if $$$ISERR(sc) {
    write "GetAuthorizationCodeEndpoint Error="
    write ..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!
  } 

  &html<
  <div class="portalLogoBox"><a class="portalLogo" href="#(url)#">Authorize for <b>ISC</b></a></div>
  </body></html>>
  Quit $$$OK
}

ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
{
  #dim %response as %CSP.Response
  set scope="openid profile scope1 scope2"
  if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error) {
    set %response.ServerSideRedirect="Web.OAUTH2.Cache2N.cls"
  }
  quit 1
}

}

Página 2

Class Web.OAUTH2.Cache2N Extends %CSP.Page
{

Parameter OAUTH2APPNAME = "demo client";

Parameter OAUTH2ROOT = "https://dk-gs2016/resserver";

Parameter SSLCONFIG = "SSL4CLIENT";

ClassMethod OnPage() As %Status
{
    &html<<html>




<body>>
    
    // Check if we have an access token from oauth2 server
    set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,"scope1 scope2",.accessToken,.idtoken,.responseProperties,.error)
    
    // Continue with further checks if an access token exists.
    // Below are all possible tests and may not be needed in all cases.
    // The JSON object which is returned for each test is just displayed.
    if isAuthorized {
        write "<h3>Authorized!</h3>",!
        
        
        // Validate and get the details from the access token, if it is a JWT.
        set valid=##class(%SYS.OAuth2.Validation).ValidateJWT(..#OAUTH2APPNAME,accessToken,"scope1 scope2",,.jsonObject,.securityParameters,.sc)
        if $$$ISOK(sc) {
            if valid {
                write "Valid JWT"_"<br>",!    
            } else {
                write "Invalid JWT"_"<br>",!    
            }
            write "Access token="
            do jsonObject.%ToJSON()
            write "<br>",!
        } else {
            write "JWT Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
        }
        write "<br>",!

        // Call the introspection endpoint and display result -- see RFC 7662.
        set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection(..#OAUTH2APPNAME,accessToken,.jsonObject)
        if $$$ISOK(sc) {
            write "Introspection="
            do jsonObject.%ToJSON()
            write "<br>",!
        } else {
            write "Introspection Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
        }
        write "<br>",!
        
        if idtoken'="" {
            // Validate and display the IDToken -- see OpenID Connect Core specification.
            set valid=##class(%SYS.OAuth2.Validation).ValidateIDToken(
                ..#OAUTH2APPNAME,
                idtoken,
                accessToken,,,
                .jsonObject,
                .securityParameters,
                .sc)
            if $$$ISOK(sc) {
                if valid {
                    write "Valid IDToken"_"<br>",!    
                } else {
                    write "Invalid IDToken"_"<br>",!    
                }
                write "IDToken="
                do jsonObject.%ToJSON()
                write "<br>",!
            } else {
                write "IDToken Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
            }
        } else {
            write "No IDToken returned"_"<br>",!
        }
        write "<br>",!
    
        // not needed for the application logic, but provides information about user that we can pass to Delegated authentication
    
        // Call the userinfo endpoint and display the result -- see OpenID Connect Core specification.
        set sc=##class(%SYS.OAuth2.AccessToken).GetUserinfo(
            ..#OAUTH2APPNAME,
            accessToken,,
            .jsonObject)
        if $$$ISOK(sc) {
            write "Userinfo="
            do jsonObject.%ToJSON()
            write "<br>",!
        } else {
            write "Userinfo Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
        }
        write "<p>",!

        /***************************************************
        *                                                  *
        *   Call the resource server and display result.   *
        *                                                  *
        ***************************************************/
                
        // option 1 - resource server - by definition - trusts data coming from authorization server,
        //     so it serves data to whoever is asking
        //  as long as access token passed to resource server is valid
        
        // option 2 - alternatively, you can use delegated authentication (OpenID Connect) 
        //  and call into another CSP application (with delegated authentication protection)
        //  - that's what we do here in this demo
        
        
        write "<4>Call resource server (delegated auth)","</h4>",!
        set httpRequest=##class(%Net.HttpRequest).%New()
        // AddAccessToken adds the current access token to the request.
        set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(
            httpRequest,,
            ..#SSLCONFIG,
            ..#OAUTH2APPNAME)
        if $$$ISOK(sc) {
            set sc=httpRequest.Get(..#OAUTH2ROOT_"/csp/portfolio/oauth2test.demoResource.cls")
        }
        if $$$ISOK(sc) {
            set body=httpRequest.HttpResponse.Data
            if $isobject(body) {
                do body.Rewind()
                set body=body.Read()
            }
            write body,"<br>",!
        }
        if $$$ISERR(sc) {
            write "Resource Server Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
        }
        write "<br>",!
    
        write "<h4>Call resource server - no auth, just token validity check","</h4>",!
        set httpRequest=##class(%Net.HttpRequest).%New()
        // AddAccessToken adds the current access token to the request.
        set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(
            httpRequest,,
            ..#SSLCONFIG,
            ..#OAUTH2APPNAME)
        if $$$ISOK(sc) {
            set sc=httpRequest.Get(..#OAUTH2ROOT_"/csp/portfolio2/oauth2test.demoResource.cls")
        }
        if $$$ISOK(sc) {
            set body=httpRequest.HttpResponse.Data
            if $isobject(body) {
                do body.Rewind()
                set body=body.Read()
            }
            write body,"<br>",!
        }
        if $$$ISERR(sc) {
            write "Resource Server Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
        }
        write "<br>",!
    } else {
        write "Not Authorized!<p>",!
        write "<a href='Web.OAUTH2.Cache1N.cls'>Authorize me</a>"
    }    
    &html<</body></html>>
    Quit $$$OK
}

}

As seguintes capturas de tela retratam o processamento:

Página de login do servidor de autenticação do OpenID Connect/autorização na instância AUTHSERVER

Página de consentimento do usuário em AUTHSERVER

E, por fim, a página resultante

Como você pode ver, lendo o código, realmente quase não há diferença em relação ao código do cliente que mostramos na parte 1. Há algo novo na página 2. São algumas informações de depuração e a verificação da validade do JWT. Depois de validar o JWT retornado, podemos realizar a introspeção dos dados do AUTHSERVER sobre a identidade do usuário. Simplesmente apresentamos essas informações nos resultados da página, mas podemos fazer mais com elas. Como no caso de uso de um médico externo mencionado acima, podemos usar as informações de identidade e transmiti-las ao servidor de recursos para fins de autenticação, se necessário. Ou apenas passar essa informação como um parâmetro para a chamada da API ao servidor de recursos.

Os próximos parágrafos descrevem como usamos as informações de identidade do usuário em mais detalhes.

Aplicativo de recurso

O servidor de recursos pode ser o mesmo servidor que o servidor de autorização/autenticação e, muitas vezes, esse é o caso. No entanto, na nossa demonstração, criamos para os dois servidores instâncias do InterSystems IRIS separadas.

Então, temos dois casos possíveis, como trabalhar com o contexto de segurança no servidor de recursos.

Alternativa 1 — sem autenticação

Esse é o caso simples. O servidor de autorização/autenticação são apenas a mesma instância do Caché. Nesse caso, podemos simplesmente transmitir o token de acesso a um aplicativo CSP, que é criado especialmente para um único propósito — enviar dados a aplicativos clientes que usam o OAUTH para autorizar a solicitação de dados.

A configuração do aplicativo CSP de recurso (chamamos de /csp/portfolio2) pode parecer com a captura de tela abaixo.

Colocamos o mínimo de segurança na definição do aplicativo, permitindo que apenas a página CSP específica seja executada.

Como opção, o servidor de recursos pode fornecer uma API REST em vez de páginas da Web clássicas. Em situações reais, o refinamento do contexto de segurança depende do usuário.

Um exemplo de código-fonte:

Class oauth2test.demoResource Extends %CSP.Page
{

ClassMethod OnPage() As %Status
{
    set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.sc)
    if $$$ISOK(sc) {
        set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection("RESSERVER resource",accessToken,.jsonObject)
        if $$$ISOK(sc) {        
            // optionally validate against fields in jsonObject

            w "<p><h3>Hello from Cach&eacute; server: <i>/csp/portfolio2</i> application!</h3>"
            w "<p>running code as <b>$username = "_$username_"</b> with following <b>$roles = "_$roles_"</b> at node <b>"_$p($zu(86),"*",2)_"</b>."
        }
    } else {
        w "<h3>NOT AUTHORIZED!</h3>"    
        w "<pre>"
        w
        i $d(%objlasterror) d $system.OBJ.DisplayError()
        w "</pre>"
    }
    Quit $$$OK
}

}

Alternativa 2 — autenticação delegada

Esse é outro caso extrema, queremos usar a identidade do usuário no servidor de recursos o máximo possível, como se o usuário estivesse trabalhando com o mesmo contexto de segurança que os usuários internos do servidor de recursos.

Uma das opções possíveis é usar a autenticação delegada.

Para essa definição funcionar, precisamos concluir mais algumas etapas para configurar o servidor de recursos.

·        Ativar a autenticação delegada

·        Fornecer a rotina ZAUTHENTICATE

·        Configurar o Web application (no nosso caso, chamamos em /csp/portfolio)

A implementação da rotina ZAUTHENTICATE é bastante simples e direta, já que confiamos no AUTHSERVER que forneceu a identidade do usuário e o escopo (perfil de segurança) dele, então basta aceitar o nome de usuário e transmitir com o escopo ao banco de dados de usuários do servidor de recursos (com a tradução necessária entre o escopo do OAUTH e as funções do InterSystems IRIS). É isso. O resto é realizado perfeitamente pelo InterSystems IRIS.

Veja o exemplo de uma rotina ZAUTHENTICATE

#include %occErrors
#include %occInclude

ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) PUBLIC
{
    set tRes=$SYSTEM.Status.OK()
    try {        
        set Properties("FullName")="OAuth account "_Username
        //set Properties("Roles")=Credentials("scope")
        set Properties("Username")=Username
        //set Properties("Password")=Password
        // temporary hack as currently we can't pass Credentials array from GetCredentials() method
        set Properties("Password")="xxx"    // we don't really care about oauth2 account password
        set Properties("Roles")=Password
    } catch (ex) {
        set tRes=$SYSTEM.Status.Error($$$AccessDenied)
    }
    quit tRes
}

GetCredentials(ServiceName,Namespace,Username,Password,Credentials) Public 
{
    s ts=$zts
    set tRes=$SYSTEM.Status.Error($$$AccessDenied)        

     try {
         If ServiceName="%Service_CSP" {
            set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.sc)
            if $$$ISOK(sc) {
                set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection("RESSERVER resource",accessToken,.jsonObject)
                if $$$ISOK(sc) {
                    // todo: watch out for potential collision between standard account and delegated (openid) one!
                    set Username=jsonObject.username
                    set Credentials("scope")=$p(jsonObject.scope,"openid profile ",2)
                    set Credentials("namespace")=Namespace
                    // temporary hack
                    //set Password="xxx"
                    set Password=$tr(Credentials("scope")," ",",")
                    set tRes=$SYSTEM.Status.OK()
                } else {
                    set tRes=$SYSTEM.Status.Error($$$GetCredentialsFailed) 
                }
            }    
        } else {
            set tRes=$SYSTEM.Status.Error($$$AccessDenied)        
        }
     } catch (ex) {
         set tRes=$SYSTEM.Status.Error($$$GetCredentialsFailed)
    }
    Quit tRes
}

A própria página CSP pode ser bastante simples:

Class oauth2test.demoResource Extends %CSP.Page
{

ClassMethod OnPage() As %Status
{
    // access token authentication is performed by means of Delegated authentication!
    // no need to do it, again, here

    // This is a dummy resource server which just gets the access token from the request and
    // uses the introspection endpoint to ensure that the access token is valid.
    // Normally the response would not be security related, but would contain some interesting
    // data based on the request parameters.
    w "<p><h3>Hello from Cach&eacute; server: <i>/csp/portfolio</i> application!</h3>"
    w "<p>running code as <b>$username = "_$username_"</b> with following <b>$roles = "_$roles_"</b> at node <b>"_$p($zu(86),"*",2)_"</b>."
    Quit $$$OK
}

}

Por fim, a configuração do Web application para /csp/portfolio

Se você estiver muito paranoico, pode definir Classes permitidas como fizemos na primeira variante. Ou, novamente, use a API REST. No entanto, isso está muito além do escopo do nosso tema.

Na próxima vez, vamos explicar classes individuais, apresentadas pelo framework OAUTH do InterSystems IRIS. Descreveremos as APIs e quando/onde chamá-las.

 

[1] Quando mencionamos o OAUTH, queremos dizer o OAuth 2.0 conforme especificado no RFC 6749 - https://tools.ietf.org/html/rfc6749. Usamos a abreviação OAUTH apenas por simplicidade.

[2] O OpenID Connect é mantido pela OpenID Foundation – http://openid.net/connect

0
0 218
Artigo Danusa Calixto · Nov. 9, 2022 10m read

Nesta série de artigos, quero apresentar e discutir várias abordagens possíveis para o desenvolvimento de software com tecnologias da InterSystems e do GitLab. Vou cobrir tópicos como:

  • Git básico
  • Fluxo Git (processo de desenvolvimento)
  • Instalação do GitLab
  • Fluxo de trabalho do GitLab
  • Entrega contínua
  • Instalação e configuração do GitLab
  • CI/CD do GitLab

No artigo anterior, abordamos os fundamentos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno e como o Git pode ser usado para desenvolver software. Ainda assim, nosso foco foi na parte da implementação do desenvolvimento de software, mas esta parte apresenta:

  • Fluxo de trabalho do GitLab — um processo completo do ciclo de vida do software, desde a ideia até o feedback do usuário
  • Entrega Contínua — uma abordagem de engenharia de software em que as equipes produzem software em ciclos curtos, garantindo que o software possa ser lançado de forma confiável a qualquer momento. Seu objetivo é construir, testar e lançar software com mais rapidez e frequência.

Fluxo de trabalho do GitLab

O fluxo de trabalho do GitLab é uma sequência lógica de possíveis ações a serem tomadas durante todo o ciclo de vida do processo de desenvolvimento de software.

O fluxo de trabalho do GitLab leva em consideração o fluxo do GitLab, que discutimos em um artigo anterior. Veja como funciona:

  1. Ideia: todas as novas propostas começam com uma ideia.
  2. Problema: a maneira mais eficaz de discutir uma ideia é criar um problema para ela. Sua equipe e seus colaboradores podem ajudar você a aprimorar e melhorar a ideia no rastreador de problemas.
  3. Plano: quando a discussão chega a um acordo, é hora de programar. Porém, primeiro, precisamos priorizar e organizar nosso fluxo de trabalho ao atribuir problemas a marcos e quadro de problemas.
  4. Código: agora estamos prontos para escrever nosso código, já que está tudo organizado.
  5. Commit: depois de satisfeitos com o rascunho, podemos enviar nosso código para um feature-branch com controle de versão. O fluxo do GitLab foi explicado em detalhes no artigo anterior.
  6. Teste: executamos nossos scripts usando o CI GitLab, para construir e testar nosso aplicativo.
  7. Revisão: assim que nosso script funcionar e nossos testes e compilações forem bem-sucedidos, estamos prontos para que nosso código seja revisado e aprovado.
  8. Staging: agora é hora de implantar nosso código em um ambiente de staging para verificar se tudo funciona como esperado ou se ainda precisamos de ajustes.
  9. Produção: quando tudo estiver funcionando como deve, é hora de implantar no nosso ambiente de produção!
  10. Feedback: agora é hora de olhar para trás e verificar qual etapa do nosso trabalho precisa ser melhorada.

Novamente, o processo em si não é novo (ou exclusivo do GitLab) e pode ser alcançado com outras ferramentas da sua escolha.

Vamos discutir várias dessas etapas e o que elas implicam. Também há documentação disponível.

Problema e plano

As etapas iniciais do fluxo de trabalho do GitLab são centradas em um problema: um recurso, bug ou outro tipo de trabalho semanticamente separado.

O problema tem várias finalidades, como:

  • Gerenciamento: um problema tem data de vencimento, pessoa designada, tempo gasto e estimativas, etc. para ajudar a monitorar a resolução do problema.
  • Administrativo: um problema faz parte de um marco, quadro kanban, que nos permite rastrear nosso software à medida que ele avança de versão para versão.
  • Desenvolvimento: um problema tem uma discussão e commits associados a ele.

A etapa de planejamento nos permite agrupar os problemas por prioridade, marco, quadro kanban e ter uma visão geral disso.

O desenvolvimento foi discutido na parte anterior, basta seguir qualquer fluxo git que quiser. Depois que desenvolvemos nosso novo recurso e o mesclamos no master: o que vem depois?

Entrega contínua

A entrega contínua é uma abordagem de engenharia de software em que as equipes produzem software em ciclos curtos, garantindo que o software possa ser lançado de forma confiável a qualquer momento. Seu objetivo é construir, testar e lançar software com mais rapidez e frequência. A abordagem ajuda a reduzir o custo, o tempo e o risco da entrega de alterações, permitindo mais atualizações incrementais para aplicativos em produção. Um processo de implantação simples e repetível é importante para a entrega contínua.

Entrega contínua no GitLab

No GitLab, a configuração da entrega contínua é definida por repositório como um arquivo de configuração YAML.

  • A configuração de entrega contínua é uma série de estágios consecutivos.
  • Cada estágio tem um ou vários scripts que são executados em paralelo.

O script define uma ação e quais condições devem ser atendidas para executá-la:

  • O que fazer (executar o comando do SO, executar um contêiner)?
  • Quando executar o script:
    • Quais são os gatilhos (commit de um branch específico)?
    • Nós o executamos se os estágios anteriores falharam?
  • Executar manualmente ou automaticamente?
  • Em que ambiente executar o script?
  • Quais artefatos salvar após a execução dos scripts (eles são carregados do ambiente para o GitLab para facilitar o acesso)?

Ambiente - é um servidor ou contêiner configurado no qual você pode executar seus scripts.

Runners executam scripts em ambientes específicos. Eles são conectados ao GitLab e executam scripts conforme necessário.

O runner pode ser implantado em um servidor, contêiner ou até mesmo na sua máquina local.

Como acontece a entrega contínua?

  1. O novo commit é enviado para o repositório.
  2. O GitLab verifica a configuração de entrega contínua.
  3. A configuração de entrega contínua contém todos os scripts possíveis para todos os casos, para que sejam filtrados para um conjunto de scripts que devem ser executados para esse commit específico (por exemplo, um commit para o branch master aciona apenas ações relacionadas a um branch master). Esse conjunto é chamado de pipeline.
  4. O pipeline é executado em um ambiente de destino e os resultados da execução são salvos e exibidos no GitLab.

Por exemplo, aqui está um pipeline executado após um commit em um branch master:

Ele consiste em quatro etapas, executadas consecutivamente

  1. O estágio de carregamento carrega o código em um servidor
  2. O estágio de teste executa testes de unidade
  3. O estágio de pacote consiste em dois scripts executados em paralelo:
    • Compilação cliente
    • Código de exportação do servidor (principalmente para fins informativos)
  4. O estágio de implantação move o cliente criado para o diretório do servidor web.

Como podemos ver, todos os scripts foram executados com sucesso. Se um dos scripts falhar, por padrão, os scripts posteriores não são executados (mas podemos alterar esse comportamento):

Se abrirmos o script, podemos ver o log e determinar por que ele falhou:

Running with gitlab-runner 10.4.0 (857480b6)
 on test runner (ab34a8c5)
Using Shell executor...
Running on gitlab-test...
&lt;span class="term-fg-l-green term-bold">Fetching changes...&lt;/span>
Removing diff.xml
Removing full.xml
Removing index.html
Removing tests.html
HEAD is now at a5bf3e8 Merge branch '4-versiya-1-0' into 'master'
From http://gitlab.eduard.win/test/testProject
 * [new branch] 5-versiya-1-1 -> origin/5-versiya-1-1
 a5bf3e8..442a4db master -> origin/master
 d28295a..42a10aa preprod -> origin/preprod
 3ac4b21..7edf7f4 prod -> origin/prod
&lt;span class="term-fg-l-green term-bold">Checking out 442a4db1 as master...&lt;/span>
&lt;span class="term-fg-l-green term-bold">Skipping Git submodules setup&lt;/span>
&lt;span class="term-fg-l-green term-bold">$ csession ensemble "##class(isc.git.GitLab).loadDiff()"&lt;/span>

[2018-03-06 13:58:19.188] Importing dir /home/gitlab-runner/builds/ab34a8c5/0/test/testProject/

[2018-03-06 13:58:19.188] Loading diff between a5bf3e8596d842c5cc3da7819409ed81e62c31e3 and 442a4db170aa58f2129e5889a4bb79261aa0cad0

[2018-03-06 13:58:19.192] Variable modified
var=$lb("MyApp/Info.cls")

Load started on 03/06/2018 13:58:19
Loading file /home/gitlab-runner/builds/ab34a8c5/0/test/testProject/MyApp/Info.cls as udl
Load finished successfully.

[2018-03-06 13:58:19.241] Variable items
var="MyApp.Info.cls"
var("MyApp.Info.cls")=""

Compilation started on 03/06/2018 13:58:19 with qualifiers 'cuk /checkuptodate=expandedonly'
Compiling class MyApp.Info
Compiling routine MyApp.Info.1
ERROR: MyApp.Info.cls(version+2) #1003: Expected space : '}' : Offset:14 [zversion+1^MyApp.Info.1]
 TEXT:  quit, "1.0" }
Detected 1 errors during compilation in 0.010s.

[2018-03-06 13:58:19.252] ERROR #5475: Error compiling routine: MyApp.Info.1. Errors: ERROR: MyApp.Info.cls(version+2) #1003: Expected space : '}' : Offset:14 [zversion+1^MyApp.Info.1]
 > ERROR #5030: An error occurred while compiling class 'MyApp.Info'
&lt;span class="term-fg-l-red term-bold">ERROR: Job failed: exit status 1
&lt;/span>

O erro de compilação causou a falha do nosso script.

Conclusão

  • O GitLab é compatível com todos os principais estágios de desenvolvimento de software.
  • A entrega contínua pode ajudar você a automatizar tarefas de construção, teste e implantação do seu software.

O que vem a seguir?

No próximo artigo, vamos:

  • Instalar o GitLab.
  • Conectá-lo a diversos ambientes com os produtos InterSystems instalados.
  • Escrever uma configuração de entrega contínua.

Vamos discutir como a entrega contínua deve funcionar.

Em primeiro lugar, precisamos de vários ambientes e branches que correspondam a eles. O código entra nesse branch e é entregue ao ambiente de destino:

AmbienteBranchEntregaQuem pode fazer enviosQuem pode mesclar
TestemasterAutomáticoDesenvolvedores  ProprietáriosDesenvolvedores  Proprietários
PreprodpreprodAutomáticoNinguémProprietários
ProdprodSemiautomático (pressionar botão para entregar)NinguémProprietários

E, como exemplo, desenvolveremos um novo recurso usando o fluxo do GitLab e o entregaremos usando a CD do GitLab.

  1. O recurso é desenvolvido em um branch de recursos.
  2. O branch de recurso é revisado e mesclado no master branch.
  3. Depois de um tempo (vários recursos mesclados), o master é mesclado com o preprod
  4. Depois de um tempo (teste do usuário, etc.), o preprod é mesclado com o prod

Veja como ficaria:

  1. Desenvolvimento e teste
    • O desenvolvedor envia o código para o novo recurso em um branch de recursos separado
    • Depois que o recurso se torna estável, o desenvolvedor mescla nosso branch de recursos no master branch
    • O código do branch master é entregue ao ambiente de teste, onde é carregado e testado
  2. Entrega para o ambiente de pré-produção
    • O desenvolvedor cria a solicitação de mesclagem do branch master para o branch de pré-produção
    • Depois de algum tempo, o proprietário do repositório aprova a solicitação de mesclagem
    • O código do branch de pré-produção é entregue ao ambiente de pré-produção
  3. Entrega para o ambiente de produção
    • O desenvolvedor cria a solicitação de mesclagem do branch de pré-produção para o branch de produção
    • Depois de algum tempo, o proprietário do repositório aprova a solicitação de mesclagem
    • O proprietário do repositório aperta o botão "Implantar"
    • O código do branch de produção é entregue ao ambiente de produção

Ou o mesmo, mas em formato gráfico:

 

0
0 302
Artigo Danusa Calixto · Set. 20, 2022 9m read

Apache Web Gateway com Docker

Olá, comunidade.

Neste artigo, vamos configurar programaticamente um Apache Web Gateway com Docker usando:

  • Protocolo HTTPS.
  • TLS\SSL para proteger a comunicação entre o Web Gateway e a instância IRIS.

imagem

Usaremos duas imagens: uma para o Web Gateway e a segunda para a instância IRIS.

Todos os arquivos necessários estão disponíveis neste repositório do GitHub.

Vamos começar com um git clone:

git clone https://github.com/lscalese/docker-webgateway-sample.git
cd docker-webgateway-sample

Prepare seu sistema

Para evitar problemas com permissões, seu sistema precisa de um usuário e um grupo:

  • www-data
  • irisowner

É necessário compartilhar arquivos de certificados com os contêineres. Se não estiverem no seu sistema, basta executar:

sudo useradd --uid 51773 --user-group irisowner
sudo groupmod --gid 51773 irisowner
sudo useradd –user-group www-data

Gere certificados

Nesta amostra, usaremos três certificados:

  1. Uso do servidor Web HTTPS.
  2. Criptografia TLS\SSL no cliente do Web Gateway.
  3. Criptografia TLS\SSL na instância IRIS.

Um script pronto para uso está disponível para gerá-los.

No entanto, você deve personalizar o sujeito do certificado. Basta editar o arquivo gen-certificates.sh.

Esta é a estrutura do argumento subj do OpenSSL:

  1. C: Código do país
  2. ST: Estado
  3. L: Local
  4. O: Organização
  5. OU: Unidade de organização
  6. CN: Nome comum (basicamente, o nome do domínio ou do host)

Fique à vontade para mudar esses valores.

# sudo é necessário devido a chown, chgrp, chmod ...
sudo ./gen-certificates.sh

Se estiver tudo certo, você verá dois novos diretórios ./certificates/ e ~/webgateway-apache-certificates/ com certificados:

ArquivoContêinerDescrição
./certificates/CA_Server.cerwebgateway,irisCertificado do servidor da autoridade
./certificates/iris_server.ceririsCertificado para a instância IRIS (usado para a criptografia de comunicação do espelho e webgateway)
./certificates/iris_server.keyirisChave privada relacionada
~/webgateway-apache-certificates/apache_webgateway.cerwebgatewayCertificado para o servidor da Web Apache
~/webgateway-apache-certificates/apache_webgateway.keywebgatewayChave privada relacionada
./certificates/webgateway_client.cerwebgatewayCertificado para criptografar a comunicação entre o webgateway e IRIS
./certificates/webgateway_client.keywebgatewayChave privada relacionada

Considere que, se houver certificados autoassinados, os navegadores da Web mostrarão alertas de segurança. Obviamente, se você tiver um certificado entregue por uma autoridade certificada, você pode usá-lo em vez de um autoassinado (especialmente para o certificado do servidor Apache).

Arquivos de configuração do Web Gateway

Observe os arquivos de configuração.

CSP.INI

Você pode ver um arquivo CSP.INI no diretório webgateway-config-files.
Ele será empurrado para dentro da imagem, mas o conteúdo pode ser modificado no ambiente de execução. Considere o arquivo como um modelo.

Na amostra, os seguintes parâmetros serão substituídos na inicialização do contêiner:

  • Ip_Address
  • TCP_Port
  • System_Manager

Consulte startUpScript.sh para ver mais detalhes. Basicamente, a substituição é realizada com a linha de comando sed.

Além disso, esse arquivo contém a configuração SSL\TLS para proteger a comunicação com a instância IRIS:

SSLCC_Certificate_File=/opt/webgateway/bin/webgateway_client.cer
SSLCC_Certificate_Key_File=/opt/webgateway/bin/webgateway_client.key
SSLCC_CA_Certificate_File=/opt/webgateway/bin/CA_Server.cer

Essas linhas são importantes. Precisamos garantir que os arquivos dos certificados estarão disponíveis para o contêiner.
Faremos isso mais tarde no arquivo docker-compose com um volume.

000-default.conf

Esse é um arquivo de configuração do Apache. Ele permite o uso do protocolo HTTPS e redireciona chamadas HTTP para HTTPS.
Os arquivos de certificado e chave privada são configurados neste arquivo:

SSLCertificateFile /etc/apache2/certificate/apache_webgateway.cer
SSLCertificateKeyFile /etc/apache2/certificate/apache_webgateway.key

Instância IRIS

Para nossa instância IRIS, configuramos somente o requisito mínimo para permitir a comunicação SSL\TLS com o Web Gateway. Isso envolve:

  1. Configuração SSL %SuperServer.
  2. Permitir a configuração de segurança SSLSuperServer.
  3. Restringir a lista de IPs que podem usar o serviço Web Gateway.

Para facilitar a configuração, config-api é usado com um arquivo de configuração JSON simples.

{
   "Security.SSLConfigs": {
       "%SuperServer": {
           "CAFile": "/usr/irissys/mgr/CA_Server.cer",
           "CertificateFile": "/usr/irissys/mgr/iris_server.cer",
           "Name": "%SuperServer",
           "PrivateKeyFile": "/usr/irissys/mgr/iris_server.key",
           "Type": "1",
           "VerifyPeer": 3
       }
   },
   "Security.System": {
       "SSLSuperServer":1
   },
   "Security.Services": {
       "%Service_WebGateway": {
           "ClientSystems": "172.16.238.50;127.0.0.1;172.16.238.20"
       }
   }
}

Nenhuma ação é necessária. A configuração será carregada automaticamente durante a inicialização do contêiner.

Imagem tls-ssl-webgateway

dockerfile

ARG IMAGEWEBGTW=containers.intersystems.com/intersystems/webgateway:2021.1.0.215.0
FROM ${IMAGEWEBGTW}
ADD webgateway-config-files /webgateway-config-files
ADD buildWebGateway.sh /
ADD startUpScript.sh /
RUN chmod +x buildWebGateway.sh startUpScript.sh && /buildWebGateway.sh
ENTRYPOINT ["/startUpScript.sh"]

Por padrão, o ponto de entrada é /startWebGateway, mas precisamos realizar algumas operações antes de iniciar o webserver. Lembre-se de que nosso arquivo CSP.ini é um modelo, e precisamos mudar alguns parâmetros (IP, porta, gerente de sistemas) na inicialização. startUpScript.sh realizará essas mudanças e executará o script de ponto de entrada inicial /startWebGateway.

Inicializando os contêineres

arquivo docker-compose

Antes de iniciar os contêineres, o arquivo docker-compose.yml precisa ser modificado:

  • **SYSTEM_MANAGER** precisa ser definido com o IP autorizado para ter acesso ao Gerenciamento do Web Gatewayhttps://localhost/csp/bin/Systems/Module.cxw Basicamente, é seu endereço IP (pode ser uma lista separada por vírgulas).

  • **IRIS_WEBAPPS** precisa ser definido com a lista dos seus aplicativos CSP. A lista é separada por espaços, por exemplo: IRIS_WEBAPPS=/csp/sys /swagger-ui. Por padrão, apenas /csp/sys é exposto.

  • As portas 80 e 443 são mapeadas. Adapte a outras portas se elas já estão em uso no seu sistema.

version: '3.6'
services:

 webgateway:
   image: tls-ssl-webgateway
   container_name: tls-ssl-webgateway
   networks:
     app_net:
       ipv4_address: 172.16.238.50
   ports:
     # mude a porta local já em uso no seu sistema.
     - "80:80"
     - "443:443"
   environment:
     - IRIS_HOST=172.16.238.20
     - IRIS_PORT=1972
     # Troque pela lista de endereços IP permitidos para abrir o gerente de sistema de CSP
     # https://localhost/csp/bin/Systems/Module.cxw 
     # veja o arquivo .env para definir a variável de ambiente.
     - "SYSTEM_MANAGER=${LOCAL_IP}"
     # a lista de web apps
     # /csp permite que o webgateway redirecione todas as solicitações que começam com /csp à instância iris
     # Você pode especificar uma lista separada por um espaço : "IRIS_WEBAPPS=/csp /api /isc /swagger-ui"
     - "IRIS_WEBAPPS=/csp/sys"
   volumes:
     # Monte os arquivos dos certificados.
     - ./volume-apache/webgateway_client.cer:/opt/webgateway/bin/webgateway_client.cer
     - ./volume-apache/webgateway_client.key:/opt/webgateway/bin/webgateway_client.key
     - ./volume-apache/CA_Server.cer:/opt/webgateway/bin/CA_Server.cer
     - ./volume-apache/apache_webgateway.cer:/etc/apache2/certificate/apache_webgateway.cer
     - ./volume-apache/apache_webgateway.key:/etc/apache2/certificate/apache_webgateway.key
   hostname: webgateway
   command: ["--ssl"]

 iris:
   image: intersystemsdc/iris-community:latest
   container_name: tls-ssl-iris
   networks:
     app_net:
       ipv4_address: 172.16.238.20
   volumes:
     - ./iris-config-files:/opt/config-files
     # Monte os arquivos dos certificados.
     - ./volume-iris/CA_Server.cer:/usr/irissys/mgr/CA_Server.cer
     - ./volume-iris/iris_server.cer:/usr/irissys/mgr/iris_server.cer
     - ./volume-iris/iris_server.key:/usr/irissys/mgr/iris_server.key
   hostname: iris
   # Carregue o arquivo de configuração IRIS ./iris-config-files/iris-config.json
   command: ["-a","sh /opt/config-files/configureIris.sh"]

networks:
 app_net:
   ipam:
     driver: default
     config:
       - subnet: "172.16.238.0/24"

Compile e comece:


docker-compose up -d --build

Os contêineres tls-ssl-iris e tls-ssl-webgateway devem ser inicializados.

Teste o acesso a Web

Página padrão do Apache

Abra a página http://localhost. Você será automaticamente redirecionado para https://localhost.
Os navegadores mostram alertas de segurança. Esse é o comportamento padrão com um certificado autoassinado, aceite o risco e continue.

imagem

Página de gerenciamento do Web Gateway

Abra https://localhost/csp/bin/Systems/Module.cxw e teste a conexão com o servidor. imagem

Portal de gerenciamento

Abra https://localhost/csp/sys/utilhome.csp

imagem

Ótimo! A amostra do Web Gateway está funcionando!

Espelho IRIS com Web Gateway

No artigo anterior, criamos um ambiente de espelho, mas faltava o Web Gateway. Agora, podemos aprimorar isso.
Um novo repositório iris-miroring-with-webgateway está disponível, incluindo o Web Gateway e mais algumas melhorias:

  1. Os certificados não são mais gerados na hora, mas em um processo separado.
  2. Os endereços IP são substituídos pelas variáveis de ambiente nos arquivos de configuração docker-compose e JSON. As variáveis são definidas no arquivo '.env'.
  3. O repositório pode ser usado como modelo.

Veja o arquivo README.md do repositório para a execução em um ambiente como este:

imagem

0
0 167
Artigo Danusa Calixto · Jul. 11, 2022 10m read


O InterSystems IRIS tem um suporte excelente para operações de criptografia, descriptografia e hashing. Na classe %SYSTEM.Encryption (https://docs.intersystems.com/iris20212/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&PRIVATE=1&CLASSNAME=%25SYSTEM.Encryption), há métodos de classes para os principais algoritmos no mercado.

Algoritmos IRIS e tipos de criptografia/descriptografia

Como você pode ver, as operações são baseadas em chaves e incluem 3 opções:

  • Chaves simétricas: as partes que executam as operações de criptografia e descriptografia compartilham a mesma chave secreta.
  • Chaves assimétricas: as partes que conduzem as operações de criptografia e descriptografia compartilham a mesma chave secreta para a criptografia. No entanto, para a descriptografia, cada parceiro tem uma chave privada. Essa chave não pode ser compartilhada com outras pessoas, pois é uma prova de identidade.
  • Hash: é usado quando você só precisa criptografar, e não descriptografar. É uma abordagem comum para o armazenamento das senhas dos usuários.

Diferenças entre a criptografia simétrica e assimétrica

  • A criptografia simétrica usa uma única chave, compartilhada entre as pessoas que precisam receber a mensagem, enquanto a criptografia assimétrica usa um par de chaves públicas e uma chave privada para criptografar e descriptografar as mensagens durante a comunicação.
  • A criptografia simétrica é uma técnica antiga, enquanto a criptografia assimétrica é relativamente nova.
  • A criptografia assimétrica foi criada para complementar o problema inerente da necessidade de compartilhar a chave em um modelo de criptografia simétrica, sem precisar compartilhar a chave usando um par de chaves pública-privada.
  • A criptografia assimétrica leva mais tempo do que a criptografia simétrica.
< width="172">
  <th>
    Criptografia simétrica
  </th>
  
  <th>
    Criptografia assimétrica
  </th>
</tr>

<tr>
  <td>
    Tamanho do texto cifrado
  </td>
  
  <td>
    Texto cifrado menor do que o arquivo de texto simples original.
  </td>
  
  <td>
    Texto cifrado maior do que o arquivo de texto simples original.
  </td>
</tr>

<tr>
  <td>
    Tamanho dos dados
  </td>
  
  <td>
    Usada para transmitir dados grandes.
  </td>
  
  <td>
    Usada para transmitir dados pequenos.
  </td>
</tr>

<tr>
  <td>
    Uso de recursos
  </td>
  
  <td>
    A criptografia simétrica de chaves funciona com baixo uso de recursos.
  </td>
  
  <td>
    A criptografia assimétrica requer alto consumo de recursos.
  </td>
</tr>

<tr>
  <td>
    Comprimento da chave
  </td>
  
  <td>
    Tamanho de 128 ou 256-bit.
  </td>
  
  <td>
    Tamanho de RSA 2048-bit ou superior.
  </td>
</tr>

<tr>
  <td>
    Segurança
  </td>
  
  <td>
    Menos segura devido ao uso de uma única chave para criptografia.
  </td>
  
  <td>
    Muito mais segura já que duas chaves diferentes estão envolvidas na criptografia e descriptografia.
  </td>
</tr>

<tr>
  <td>
    Número de chaves
  </td>
  
  <td>
    A criptografia simétrica usa uma única chave para a criptografia e descriptografia.
  </td>
  
  <td>
    A criptografia assimétrica usa duas chaves diferentes para a criptografia e descriptografia
  </td>
</tr>

<tr>
  <td>
    Técnicas
  </td>
  
  <td>
    É uma técnica antiga.
  </td>
  
  <td>
    É uma técnica moderna.
  </td>
</tr>

<tr>
  <td>
    Confidencialidade
  </td>
  
  <td>
    Uma única chave para a criptografia e descriptografia tem o risco de ser comprometida.
  </td>
  
  <td>
    Duas chaves são criadas separadamente para a criptografia e descriptografia, o que elimina a necessidade de compartilhar uma chave.
  </td>
</tr>

<tr>
  <td>
    Velocidade
  </td>
  
  <td>
    A criptografia simétrica é uma técnica rápida.
  </td>
  
  <td>
    A criptografia assimétrica é mais lenta em termos de velocidade.
  </td>
</tr>

<tr>
  <td>
    Algoritmos
  </td>
  
  <td>
    RC4, AES, DES, 3DES e QUAD.
  </td>
  
  <td>
    RSA, Diffie-Hellman e ECC.
  </td>
</tr>
Principais diferenças

Fonte: https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences 

Usando a classe %SYSTEM.Encryption para criptografia, descriptografia e hash

Para treinar o suporte do IRIS para as operações de criptografia, descriptografia e hash, acesse https://github.com/yurimarx/cryptography-sample e siga estas etapas:

  1. Use o git pull ou clone o repositório em qualquer diretório local
$ git clone https://github.com/yurimarx/cryptography-samples.git
  1. Abra um terminal Docker nesse diretório e execute:
$ docker-compose build
  1. Execute o contêiner IRIS:
$ docker-compose up -d
  1. Abra o terminal IRIS:
$ docker-compose exec iris iris session iris -U IRISAPP

IRISAPP>
  1. Para a criptografia assimétrica com RSA, execute:
IRISAPP>Set ciphertext = ##class(dc.cryptosamples.Samples).DoRSAEncrypt("InterSystems")
IRISAPP>Write ciphertext
Ms/eR7pPmE39KBJu75EOYIxpFEd7qqoji61EfahJE1r9mGZX1NYuw5i2cPS5YwE3Aw6vPAeiEKXF
rYW++WtzMeRIRdCMbLG9PrCHD3iQHfZobBnuzx/JMXVc6a4TssbY9gk7qJ5BmlqRTU8zNJiiVmd8
pCFpJgwKzKkNrIgaQn48EgnwblmVkxSFnF2jwXpBt/naNudBguFUBthef2wfULl4uY00aZzHHNxA
bi15mzTdlSJu1vRtCQaEahng9ug7BZ6dyWCHOv74O/L5NEHI+jU+kHQeF2DJneE2yWNESzqhSECa
ZbRjjxNxiRn/HVAKyZdAjkGQVKUkyG8vjnc3Jw==
  1. Para a descriptografia assimétrica com RSA, execute:
IRISAPP>Set plaintext = ##class(dc.cryptosamples.Samples).DoRSADecrypt(ciphertext)
IRISAPP>Write plaintext
InterSystems
  1. Para a criptografia simétrica com AES CBC, execute:
IRISAPP>Do ##class(dc.cryptosamples.Samples).DoAESCBCEncrypt("InterSystems")
8sGVUikDZaJF+Z9UljFVAA==
  1. Para a descriptografia simétrica com AES CBC, execute:
IRISAPP>Do ##class(dc.cryptosamples.Samples).DoAESCBCDecrypt("8sGVUikDZaJF+Z9UljFVAA==")
InterSystems
  1. Para uma abordagem antiga com hash MD5, execute:
IRISAPP>Do ##class(dc.cryptosamples.Samples).DoHash("InterSystems")
rOs6HXfrnbEY5+JBdUJ8hw==
  1. Para uma abordagem recomendada com hash SHA, execute:
IRISAPP>Do ##class(dc.cryptosamples.Samples).DoSHAHash("InterSystems")
+X0hDlyoViPlWOm/825KvN3rRKB5cTU5EQTDLvPWM+E=
  1. Para sair do terminal:
Digite HALT ou H (não diferencia maiúsculas de minúsculas)

 

Sobre o código-fonte

1. Sobre a chave simétrica

# para usar com criptografia/descriptografia simétrica
ENVSECRETKEY=InterSystemsIRIS

No Dockerfile, foi criada uma chave do ambiente para ser usada como chave secreta em operações simétricas.

2. Sobre a chave assimétrica

# para usar com criptografia/descriptografia assimétrica, execute openssl req  -new -x509 -sha256 -config example-com.conf -newkey rsa:2048 -nodes -keyout example-com.key.pem  -days 365 -out example-com.cert.pem

No Dockerfile, foram geradas uma chave privada e uma chave pública para serem usadas com operações assimétricas.

3. Criptografia simétrica

//Amostra de chaves simétricas para criptografia
 
ClassMethodDoAESCBCEncrypt(plaintextAs%String)As%Status
{
    // converter para utf-8
    Settext=$ZCONVERT(plaintext,"O","UTF8")
   
    // definir uma chave secreta
    Setsecretkey=$system.Util.GetEnviron("SECRETKEY")
    SetIV=$system.Util.GetEnviron("SECRETKEY")
   
    // criptografar um texto
    Settext=$SYSTEM.Encryption.AESCBCEncrypt(text,secretkey,IV)
    Setciphertext=$SYSTEM.Encryption.Base64Encode(text)
   
    Writeciphertext
}

A operação AES CBC Encrypt foi usada para criptografar textos.
A codificação base64 retorna os resultados como um texto organizado/legível para o usuário.

4. Descriptografia simétrica

//Amostra de chaves simétricas para descriptografia
 
ClassMethodDoAESCBCDecrypt(ciphertextAs%String)As%Status
{
    // definir uma chave secreta
    Setsecretkey=$system.Util.GetEnviron("SECRETKEY")
    SetIV=$system.Util.GetEnviron("SECRETKEY")
   
    // descriptografar um texto
    Settext=$SYSTEM.Encryption.Base64Decode(ciphertext)
    Settext=$SYSTEM.Encryption.AESCBCDecrypt(text,secretkey,IV)
   
    Setplaintext=$ZCONVERT(text,"I","UTF8")
    Writeplaintext
}

A operação AES CBC Decrypt foi usada para descriptografar textos.
A decodificação base64 retorna o texto criptografado a um binário, para ser usado na descriptografia.

5. Criptografia assimétrica

//Amostra de chaves assimétricas para criptografia
 
ClassMethodDoRSAEncrypt(plaintextAs%String)As%Status
{
    // obter certificado público
    SetpubKeyFileName="/opt/irisbuild/example-com.cert.pem"
    SetobjCharFile=##class(%Stream.FileCharacter).%New()
    SetobjCharFile.Filename=pubKeyFileName
    SetpubKey=objCharFile.Read()
 
    // criptografar usando RSA
    Setbinarytext=$System.Encryption.RSAEncrypt(plaintext,pubKey)
    Setciphertext=$SYSTEM.Encryption.Base64Encode(binarytext)
   
    Returnciphertext
}

É preciso obter o conteúdo do arquivo da chave pública para criptografar com RSA.
A operação RSA Encrypt foi usada para criptografar textos.

6. Descriptografia assimétrica

//Amostra de chaves assimétricas para descriptografia
 
ClassMethodDoRSADecrypt(ciphertextAs%String)As%Status
{
    // obter chave pública
    SetprivKeyFileName="/opt/irisbuild/example-com.key.pem"
    SetprivobjCharFile=##class(%Stream.FileCharacter).%New()
    SetprivobjCharFile.Filename=privKeyFileName
    SetprivKey=privobjCharFile.Read()
 
    // obter ciphertext em formato binário
    Settext=$SYSTEM.Encryption.Base64Decode(ciphertext)
 
    // descriptografar texto usando RSA
    Setplaintext=$System.Encryption.RSADecrypt(text,privKey)
 
    Returnplaintext
}

É preciso obter o conteúdo do arquivo da chave privada para descriptografar com RSA.
A operação RSA Decrypt foi usada para descriptografar textos.

7. Texto com hash usando MD5 (abordagem antiga)

//Amostra de hash
 
ClassMethodDoHash(plaintextAs%String)As%Status
{
    // converter para utf-8
    Settext=$ZCONVERT(plaintext,"O","UTF8")
   
    // hash de um texto
    Sethashtext=$SYSTEM.Encryption.MD5Hash(text)
   
    Setbase64text=$SYSTEM.Encryption.Base64Encode(hashtext)
 
    // converter para texto hex para seguir as melhores práticas
    Sethextext=..GetHexText(base64text)
 
    // retornar usando minúsculas
    Write$ZCONVERT(hextext,"L")
}

A operação MD5 Hash fará a criptografia do texto e não será possível descriptografar.
O hash com MD5 não é recomendado para novos projetos por não ser considerado seguro. Por isso, foi substituído por SHA. O InterSystems IRIS oferece compatibilidade com SHA (veja nosso próximo exemplo).

8. Texto com hash usando SHA (abordagem recomendada)

Usaremos o método de hash SHA-3 para esta amostra. De acordo com a documentação do InterSystems, esse método gera um hash usando um dos Algoritmos de Hash Seguro dos EUA - 3. Consulte a Publicação 202 dos Federal Information Processing Standards para saber mais. 

//Hash usando SHA
 
ClassMethodDoSHAHash(plaintextAs%String)As%Status
{
    // converter para utf-8
    Settext=$ZCONVERT(plaintext,"O","UTF8")
   
    // hash de um texto
    Sethashtext=$SYSTEM.Encryption.SHA3Hash(256,text)
   
    Setbase64text=$SYSTEM.Encryption.Base64Encode(hashtext)
 
    // converter para texto hex para seguir as melhores práticas
    Sethextext=..GetHexText(base64text)
 
    // retornar usando minúsculas
    Write$ZCONVERT(hextext,"L")
}

No método SHA, é possível definir o comprimento do bit usado em uma operação de hash. Quanto maior o número de bits, mais difícil é decifrar o hash. No entanto, o processo de hashing também fica mais lento. Na amostra, usamos 256 bits. Você pode escolher estas opções de comprimento de bit:

  • 224 (SHA-224)
  • 256 (SHA-256)
  • 384 (SHA-384)
  • 512 (SHA-512)
0
0 273
Artigo Angelo Bruno Braga · Fev. 25, 2022 27m read

Neste artigo iremos construir uma configuração IRIS de alta disponibilidade utilizando implantações Kubernetes com armazenamento persistente distribuído substituindo o "tradicional" espelhamento IRIS. Esta implantação será capaz de tolerar falhas relacionadas a infraestrutura como falhas em nós, armazenamento e de Zonas de Disponibilidade. A abordagem descrita reduz muito a complexidade da implantação em detrimento um objetivo de tempo de recuperação (RTO) ligeiramente estendido.

Figura 1 - Espelhamento Tradicional x Kubernetes com Armazenamento Distribuído

Todos os códigos fonte deste artigo estão disponíveis em https://github.com/antonum/ha-iris-k8s
TL;DR

Assumindo que você possui um cluster com 3 nós e também uma certa familiaridade com o Kubernetes – vá em frente:

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml
kubectl apply -f https://github.com/antonum/ha-iris-k8s/raw/main/tldr.yaml

Se você não tem certeza sobre o que as duas linhas acima fazem ou não possui o sistema onde executá-las - pule para a seção “Requisitos de Alta Disponibilidade". Iremos explicar tudo detalhadamente conforme evoluirmos no artigo.

Esta primeira linha instala o Longhorn - armazenamento distribuído Kubernetes de código aberto. A segunda instala o InterSystems IRIS, utilizando um volume baseado no Longhorn para o Durable SYS.

Aguarde até que todos os pods atinjam o estado de "em execução". kubectl get pods -A

Agora você deve ser capaz de acessar o portal de administração do IRIS em http://<IP Público do IRIS>:52773/csp/sys/%25CSP.Portal.Home.zen  (a senha padrão é 'SYS') e a linha de comando do IRIS através de:

kubectl exec -it iris-podName-xxxx -- iris session iris

Simule a Falha

Agora pode começar a bagunçar as coisas. Mas, antes de fazê-lo, tente adicionar alguns dados na base de dados para se certificar que estarão lá quando o IRIS voltar a ficar disponível.

kubectl exec -it iris-6d8896d584-8lzn5 -- iris session iris
USER>set ^k8stest($i(^k8stest))=$zdt($h)_" running on "_$system.INetInfo.LocalHostName()
USER>zw ^k8stest
^k8stest=1
^k8stest(1)="01/14/2021 14:13:19 running on iris-6d8896d584-8lzn5"

Nossa "engenharia do caos" inicia aqui:

# Parar o IRIS - Contêiner será reiniciado automaticamente 
kubectl exec -it iris-6d8896d584-8lzn5 -- iris stop iris quietly
 
# Deletar o  pod - O Pod será recriado 
kubectl delete pod iris-6d8896d584-8lzn5
 
# "Drenar à força" o nó que está servindo o pod IRIS - O Pod seria recriado em outro nó
kubectl drain aks-agentpool-29845772-vmss000001 --delete-local-data --ignore-daemonsets --force
 
# Deletar o nó - O Pod seria recriado em outro nó
# bem... você não pode realmente fazê-lo com o kubectl. Localize a instância ou a VM e a destrua.
# se você possuir acesso à maquina - desligue a força ou desconecte o cabo de rede. Estou falando sério!

Requisitos de Alta Disponibilidade

 

Estamos construindo um sistema que possa tolerar uma falha das seguintes:

  • Instância IRIS dentro de um contêiner/VM. Falha a nível do IRIS.
  • Falha no Pod/Contêiner.
  • Indisponibilidade temporária do nó de cluster individual. Um bom exemplo seria quando uma Zona de Disponibilidade fica temporariamente fora do ar.
  • Falha permanente do nó de cluster individual ou disco.

Basicamente os cenários que executamos na seção ˜Simule a falha".

Se alguma destas falhas ocorrer, o sistema deverá se recuperar sem que necessite de nenhum envolvimento humano e sem que ocorra nenhuma perda de dados.. Tecnicamente existem limites do que a persistência de dados garante. O IRIS por si só provê com base no Ciclo do Journal e no uso de transações em uma aplicação: https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=GCDI_journal#GCDI_journal_writecycle De qualquer forma, estamos falando de menos de dois segundos de objetivo de ponto de recuperação (RPO).

Outros componentes do sistema (Serviço de APIs Kubernetes, base de dados etcd, serviço de Balanceamento de Carga, DNS e outros) estão fora do escopo e são gerenciados tipicamente pelo Serviço Gerenciado Kubernetes como o Azure AKS ou AWS EKS, então assumimos que eles já estão em alta disponibilidade.

Outra forma de se ver – somos responsáveis por lidar com falhas individuais de componentes e armazenamento, assumindo que o resto é tratado pelo provedor de infraestrutura/nuvem.

Arquitetura

Quando se trata de alta disponibilidade para o InterSystems IRIS, a recomendação tradicional é a utilização de Espelhamento. Utilizando o Espelhamento você terá duas instâncias ligadas do IRIS replicando de forma síncrona os dados. Cada nó mantém uma cópia completa da base de dados e, se o nó principal falhar, os usuários reconectam no nó Backup. Essencialmente, com a abordagem de uso do Espelhamento, o IRIS é responsável pela redundância tanto de computação quanto de armazenamento.

Com os servidores de espelhamento implantados em zonas de disponibilidade distintas o espelhamento provê a redundância necessária tanto para falhas de computação quanto para falhas de armazenamento e permite o excelente objetivo de tempo de recuperação (RTO - tempo necessário para que um sistema se recupere após uma falha) de apenas poucos segundos. Você pode encontrar o modelo de implantação para o IRIS Espelhado na Nuvem AWS aqui: https://community.intersystems.com/post/intersystems-iris-deployment%C2%A0guide-aws%C2%A0using-cloudformation-template

O lado menos bonito do espelhamento é a complexidade de configurá-lo, realizando procedimentos de backups e restore e lidando com a falta de replicação para configurações de segurança e arquivos locais que não os de bases de dados.

Orquestradores de contêineres como o Kubernetes (espere, estamos em 2021… exitem outros?!) proveem uma redundância computacional através da implantação de objetosautomaticamente reiniciando o Pod/Contêiner IRIS no caso de falha. É por isso que você vê apenas um nó IRIS executando no diagrama de arquitetura Kubernetes. Ao invés de manter um segundo nó de IRIS executando nós terceirizamos a disponibilidade de computação para o Kubernetes. O Kubernetes se certificará que o pod IRIS pode ser recriado no caso de falha do pod original por qualquer motivo.

Figura 2 Cenario de Failover

Tudo bem até agora… Se o nó do IRIS falhar, o Kubernetes apenas cria um novo. Dependendo do seu cluster, ele leva algo entre 10 a 90 segundos para trazer o IRIS de volta ao ar após uma falha de computação. É um passo atrás comparado com apenas alguns segundos no espelhamento mas, se é algo que você pode tolerar no caso de um evento indesejado, a recompensa é a grande redução da complexidade. Sem configuração de espelhamento e nem configurações de segurança e replicações de arquivos com que se preocupar.

Sinceramente, se você se logar em um contêiner, executando o IRIS no Kubernetes, você nem mesmo perceberá que está executando em um ambiente de alta disponibilidade. Tudo parece e se comporta como uma implantação de uma instância individual de IRIS.

Espere, e quanto ao armazenamento? Estamos lidando com um banco de dados … Seja qual for o cenário de falha que possamos imaginar, nosso sistema deverá cuidar da persistência dos dados também. O Espelhamento depende da computação, local no nó IRIS. Se o nó morre ou fica temporariamente indisponível – o armazenamento para o nó também o fica. É por isso que na configuração de espelhamento o IRIS cuida da replicação das bases de dados no nível do IRIS.

Precisamos de um armazenamento que possa não só preservar o estado da base de dados na reinicialização do contêiner mas também possa prover redundância em casos como a queda do nó ou de um segmento inteiro da rede (Zona de Disponibilidade). A apenas alguns anos atrás não existia uma resposta fácil para isso.Como você pode supor a partir do diagrama acima – temos uma baita resposta agora. É chamada de armazenamento distribuído de contêineres.

O armazenamento distribuído abstrai os volumes de hospedeiros subjacentes e os apresenta como um armazenamento conjunto disponível para todos os nós do cluster k8s. Nós utilizamos o Longhorn https://longhorn.io neste artigo; é grátis, de código aberto e bem fácil de instalar. Mas, você também pode verificar outros como o OpenEBS, Portworx e StorageOS que devem disponibilizar as mesmas funcionalidades. Rook Ceph é outro projeto de incubação CNCF a se considerar. No outro lado do espectro existem soluções de armazenamento de nível empresarial como o NetApp, PureStorage e outros.

Guia Passo a Passo

Na seção TL;DR nós instalamos tudo de uma vez. O Apêndice B lhe guiará através da instalação passo a passo e dos procedimentos de validação.

Armazenamento Kubernetes

Vamos voltar um pouco por um segundo e falar sobre contêineres e armazenamento em geral e como o IRIS se encaixa no cenário.

Por padrão todos os dados dentro do contêiner são efêmeros. Quando o contêiner morre, o dado desaparece. No Docker, você pode utilizar o conceito de volumes. Essencialmente isto permite que você exponha o diretório de seu SO hospedeiro para o contêiner.

docker run --detach
  --publish 52773:52773
  --volume /data/dur:/dur
  --env ISC_DATA_DIRECTORY=/dur/iconfig
  --name iris21 --init intersystems/iris:2020.3.0.221.0

No exemplo acima estamos iniciando o contêiner IRIS e fazendo com que o diretório local do hospedeiro ‘/data/dur’ fique acessível no ponto de montagem ‘/dur’ do contêiner. Desta forma, se o contêiner estiver armazenando qualquer coisa neste diretório, ela será preservada e disponível para utilização quando o próximo contêiner iniciar.

Do lado IRIS das coisas, podemos instruir o IRIS para armazenar todos os dados que devem sobreviver ao reinicio do contêiner em um diretório determinado especificando ISC_DATA_DIRECTORY. Durable SYS é o nome da funcionalidade do IRIS que você pode precisar dar uma olhada na documentação https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=ADOCK#ADOCK_iris_durable_running

No Kubernetes a sintaxe é diferente mas os conceitos são os mesmos.

Aqui está a Implantação Kubernetes básica para IRIS.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: iris
spec:
  selector:
    matchLabels:
      app: iris
  strategy:
    type: Recreate
  replicas: 1
  template:
    metadata:
      labels:
        app: iris
    spec:
      containers:
      - image: store/intersystems/iris-community:2020.4.0.524.0
        name: iris
        env:
        - name: ISC_DATA_DIRECTORY
          value: /external/iris
        ports:
        - containerPort: 52773
          name: smp-http
        volumeMounts:
        - name: iris-external-sys
          mountPath: /external
      volumes:
      - name: iris-external-sys
        persistentVolumeClaim:
          claimName: iris-pvc

 

Na especificação de implantação acima, a parte ‘volumes’ lista os volumes de armazenamento. Eles podem estar disponíveis fora do contêiner através do Requisição de Volume Persistente (PersistentVolumeClaim) como ‘iris-pvc’. O 'volumeMounts' expõe este volume dentro do contêiner. ‘iris-external-sys’ é o identificador que amarra a montagem do volume ao volume específico. Na verdade, podemos ter múltiplos volumes e este nome é utilizado apenas para distinguir um de outro. Você pode chamá-lo de ‘steve’ se quiser.

A variável de ambiente ISC_DATA_DIRECTORY, já familiar, instrui o IRIS a utilizar um ponto de montagem específico para armazenar todos os dados que precisam sobreviver ao reinício do contêiner.

Agora vamos dar uma olhada na Requisição de Volume Persistente iris-pvc.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: iris-pvc
spec:
  storageClassName: longhorn
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

 

Bastante direto. Requisitando 10 gigabytes, montado como Read/Write em apenas um nó, utilizando a classe de armazenamento de ‘longhorn’.

Aquela storageClassName: longhorn é de fato crítica aqui.

Vamos olhar quais classes de armazenamento estão disponíveis no meu cluster AKS:

kubectl get StorageClass
NAME                             PROVISIONER                     RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
azurefile                        kubernetes.io/azure-file        Delete          Immediate           true                   10d
azurefile-premium                kubernetes.io/azure-file        Delete          Immediate           true                   10d
default (default)                kubernetes.io/azure-disk        Delete          Immediate           true                   10d
longhorn                         driver.longhorn.io              Delete          Immediate           true                   10d
managed-premium                  kubernetes.io/azure-disk        Delete          Immediate           true                   10d

Existem poucas classes de armazenamento do Azure, instaladas por padrão e uma do Longhorn que instalamos como parte de nosso primeiro comando:

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml

Se você comentar #storageClassName: longhorn na definição da Requisição de Volume Persistente, será utilizada a classe de armazenamento que estiver marcada como “default” que é o disco regular do Azure.

Para ilustrar porquê precisamos de armazenamento distribuído vamos repetir o experimento da “engenharia do caos” que descrevemos no início deste artigo sem o armazenamento longhorn. Os dois primeiros cenários (parar o IRIS e deletar o Pod) deveriam completar com sucesso e os sistemas deveriam se recuperar ao estado operacional. Ao tentar tanto drenar ou destruir o nó deveria deixar o sistema em estado de falha.

#drenar o nó a força
kubectl drain aks-agentpool-71521505-vmss000001 --delete-local-data --ignore-daemonsets

kubectl describe pods ...   Type     Reason            Age                  From               Message   ----     ------            ----                 ----               -------   Warning  FailedScheduling  57s (x9 over 2m41s)  default-scheduler  0/3 nodes are available: 1 node(s) were unschedulable, 2 node(s) had volume node affinity conflict.

Essencialmente, o Kubernetes tentará reiniciar o pod IRIS pod no cluster mas, o nó onde ele iniciou originalmente não está disponível e os outros dois nós apresentam “conflito de afinidade de nó de volume”. Com este tipo de armazenamento o volume só está disponível no nó onde ele foi originalmente criado, visto que ele é basicamente amarrado ao disco disponível no nó hospedeiro.

Com o longhorn como classe de armazenamento, tanto o experimento “drenar a força” quanto o “destruir nó” funcionam com sucesso e o pod IRIS retorna a operação brevemente. Para conseguí-lo o Longhorn assume controle dos armazenamentos disponíveis dos 3 nós do cluster e replica os dados através deles. O Longhorn prontamente repara o armazenamento do cluster se um dos nós fica permanentemente indisponível. No nosso cenário “Destruir nó” o pod IRIS é reiniciado em outro nó rapidamente utilizando as replicas nos dois outros volumes remanescentes.  Então, o AKS provisiona um novo nó para substituir o nó perdido e assim que ele está pronto, o Longhorn entra em ação e reconstrói os dados necessários no novo nó. Tudo é automático, sem seu envolvimento.

Figura 3 Longhorn reconstruindo a réplica do volume no nó substituído

Mais sobre implantação k8s

Vamos dar uma olhada em alguns outros aspectos de nossa implantação:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: iris
spec:
  selector:
    matchLabels:
      app: iris
  strategy:
    type: Recreate
  replicas: 1
  template:
    metadata:
      labels:
        app: iris
    spec:
      containers:
      - image: store/intersystems/iris-community:2020.4.0.524.0
        name: iris
        env:
        - name: ISC_DATA_DIRECTORY
          value: /external/iris
        - name: ISC_CPF_MERGE_FILE
          value: /external/merge/merge.cpf
        ports:
        - containerPort: 52773
          name: smp-http
        volumeMounts:
        - name: iris-external-sys
          mountPath: /external
        - name: cpf-merge
          mountPath: /external/merge
        livenessProbe:
          initialDelaySeconds: 25
          periodSeconds: 10
          exec:
            command:
            - /bin/sh
            - -c
            - "iris qlist iris | grep running"
      volumes:
      - name: iris-external-sys
        persistentVolumeClaim:
          claimName: iris-pvc
      - name: cpf-merge
        configMap:
          name: iris-cpf-merge

 

strategy: Recreate, replicas: 1 informa ao Kubernetes que em algum momento ele deve manter uma e exatamente uma instância de do pod IRIS executando. Isto é o que dá conta do nosso cenário “deletar pod”.

A seção livenessProbe garante que o IRIS está sempre ativo no contêiner e trata o cenário “IRIS está fora”. initialDelaySeconds garante algum tempo para que o IRIS inicie. Você pode querer aumentá-lo se o IRIS estiver levando um tempo considerável para iniciar em sua implementação.

CPF MERGE funcionalidade do IRIS que lhe permite modificar o conteúdo do arquivo de configuração iris.cpf durante a inicialização do contêiner. Veja https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=RACS_cpf#RACS_cpf_edit_merge para a documentação referente a ela. Neste exemplo estou utilizando o Kubernetes Config Map para gerenciar o conteúdo do arquivo mesclado: https://github.com/antonum/ha-iris-k8s/blob/main/iris-cpf-merge.yaml Aqui ajustamos os valores para os global buffers e gmheap, utilizados pela instância do IRIS, mais tudo que você pode encontrar no arquivo iris.cpf. Você pode até mesmo alterar a senha padrão do IRIS utilizando o campo `PasswordHash`no arquivo CPF Merge. Leia mais em: https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=ADOCK#ADOCK_iris_images_password_auth

Além da Requisição de Volume Persistente https://github.com/antonum/ha-iris-k8s/blob/main/iris-pvc.yaml da implantação https://github.com/antonum/ha-iris-k8s/blob/main/iris-deployment.yaml e ConfigMap com o conteúdo do CPF Merge https://github.com/antonum/ha-iris-k8s/blob/main/iris-cpf-merge.yaml nossa implantação precisa de um serviço que exponha a implantação IRIS para a Internet pública: https://github.com/antonum/ha-iris-k8s/blob/main/iris-svc.yaml

kubectl get svc
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)           AGE
iris-svc     LoadBalancer   10.0.18.169   40.88.123.45   52773:31589/TCP   3d1h
kubernetes   ClusterIP      10.0.0.1      <none>          443/TCP           10d

O IP Externo do iris-svc pode ser utilizado para acessar o portal de administração do IRIS através de  http://40.88.123.45:52773/csp/sys/%25CSP.Portal.Home.zen. A senha padrão é 'SYS'.

Backup/Restore e Dimensionamento do Armazenamento

Longhorn disponibiliza uma interface web para usuários para configurar e gerenciar volumes.

Identificar o pod, executar o componente de interface para usuários (longhorn-ui) e estabelecer um encaminhamento de portas com kubectl:

kubectl -n longhorn-system get pods
# note the longhorn-ui pod id.

kubectl port-forward longhorn-ui-df95bdf85-gpnjv 9000:8000 -n longhorn-system

A interface para usuários Longhorn ficará disponível em http://localhost:9000

Figura 4 Longhorn UI

Além da alta disponibilidade, a maioria das soluções de armazenamento para contêineres disponibilizam opções convenientes para backup, snapshots e restore. Os detalhes são específicos para cada implantação mas a convenção comum é de que o backup é associado ao VolumeSnapshot. Também é assim para o Longhorn. Dependendo da sua versão do Kubernetes e do seu provedor você também pode precisar instalar o volume snapshotter https://github.com/kubernetes-csi/external-snapshotter

`iris-volume-snapshot.yaml` é um exemplo de um snapshot de volume. Antes de utilizá-lo você deve configurar backups ou para um bucket S3 ou para um volume NFS no Longhorn. https://longhorn.io/docs/1.0.1/snapshots-and-backups/backup-and-restore/set-backup-target/

# Realizar um backup consistente do volume IRIS
kubectl apply -f iris-volume-snapshot.yaml

Para o IRIS é recomendado que você execute o External Freeze antes de realizar o backup/snapshot e então o Thaw depois. Veja os detalhes aqui: https://docs.intersystems.com/irisforhealthlatest/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&CLASSNAME=Backup.General#ExternalFreeze  

Para aumentar o tamanho do volume IRIS - ajuste a requisição de armazenamento na requisição de volume persistente (arquivo `iris-pvc.yaml`), utilizado pelo IRIS.

...
  resources:
    requests:
      storage: 10Gi #altere este valor para o necessário

Então, aplique novamente a especificação pvc. O Longhorn não consegue aplicar esta alteração enquanto o volume está conectado ao Pod em execução. Temporariamente altere o contador de réplicas para zero na implantação para que o tamanho do volume possa ser aumentado.

Alta Disponibilidade – Visão Geral

No início deste artigo nós definimos alguns critérios para alta disponibilidade. Aqui está como conseguimos alcançá-los com esta arquitetura:

Domínio de Falha

Mitigado automaticamente por

Instância IRIS no contêiner/VM. Falha no nível do IRIS.

Sonda Deployment Liveness reinicia o contêiner no caso do IRIS estar fora

Falha de Pod/Contêiner.

Implantação recria o Pod

Indisponibilidade temporária de um nó do cluster individual. Um bom exemplo seria uma Zona de Disponibilidade fora.

Implantação recria o pod em outro nó. O Longhorn torna os dados disponíveis em outro nó.

Falha permanente de um nó de cluster individual ou disco.

Mesmo do anteiror + k8s cluster autoscaler substituindo um nó danificado por um novo. O Longhorn reconstrói os dados no novo nó.

Zumbis e outras coisas a considerar

Se você estiver familiarizado em executar o IRIS em contêineres Docker, você já deve ter utilizado a flag `--init`.

docker run --rm -p 52773:52773 --init store/intersystems/iris-community:2020.4.0.524.0

O objetivo desta flag é previnir a formação de processos "zumbis". No Kubernetes, você pode tanto utilizar ‘shareProcessNamespace: true’ (considerações de segurança se aplicam) ou em seus próprios contêineres utilizar `tini`. Exemplo de Dockerfile com tini:

FROM iris-community:2020.4.0.524.0
...
# Add Tini
USER root
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
USER irisowner
ENTRYPOINT ["/tini", "--", "/iris-main"]

Desde 2021, todas as imagens de contêineres disponibilizadas pela InterSystems incluiria tini por padrão.

Você pode posteriormente diminuir o tempo de recuperação para os cenários “Drenar a força o nó/destruir nó” ajustando poucos parâmetros:

Política de Deleção de Pods do Longhorn https://longhorn.io/docs/1.1.0/references/settings/#pod-deletion-policy-when-node-is-down e despejo baseado em taint do kubernetes: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#taint-based-evictions

Disclaimer

Como funcionário InterSystems, Eu tenho que colocar isto aqui: O Longhorn é utilizado neste artigo como um exemplo de Armazenamento em Blocos Distribuído para Kubernetes. A InterSystems não valida e nem emite uma declaração de suporte oficial para soluções ou produtos de armazenamento individual. Você precisa testar e validar se qualquer solução específica de armazenamento atende a suas necessidades.

Solucões para armazenamento distribuído podem possuir características substancialmente distintas de performance., quando comparadas a armazenamento em nó local. Especialmente para operações de escrita, onde os dados devem ser escritos em múltiplas localidades antes de ser considerado em estado persistente. Certifique-se de testar suas cargas de trabalho e entender o comportamento específico, bem como as opções que seu driver para Interface de Armazenamento de Contêiner (CSI) oferece.

Basicamente, a InterSystems não valida e/ou endossa soluções específicas de armazenamento como o Longhorn da mesma forma que não valida marcas de HDs ou fabricantes de hardware para servidores. Eu pessoalmente achei o Longhorn fácil de se utilizar e seu time de desenvolvimento extremamente responsivo e útil na página do projeto no GitHub. https://github.com/longhorn/longhorn 

Conclusão

O ecossistema Kubernetes evoluiu de forma significante nos últimos anos e, com a utilização de soluções de armazenamento em blocos distribuído, você pode agora construir uma configuração de Alta Disponibilidade que pode manter uma instância IRIS, nó de cluster e até mesmo falhas de Zonas de Disponibilidade.

Você pode terceirizar a alta disponibilidade de computação e armazenamento para componentes do Kubernetes, resultando em um sistema significativamente mais simples de se configurar e manter, comparando-se ao espelhamento tradicional do IRIS. Da mesma forma, esta configuração pode não lhe prover o mesmo RTO e nível de performance de armazenamento que uma configuração de Espelhamento.

Neste artigo criamos uma configuração IRIS de alta disponibilidade utilizando o Azure AKS como Kubernetes gerenciado e o sistema de armazenamento distribuído Longhorn. Você pode explorar múltiplas alternativas como AWS EKS, Google Kubernetes Engine para K8s gerenciados, StorageOS, Portworx e OpenEBS para armazenamento distribuído para contêiner ou mesmo soluções de armazenamento de nível empresarial como NetApp, PureStorage, Dell EMC e outras.

Apêndice A. Criando um Cluster Kubernetes na nuvem

Serviço Gerenciado Kubernetes de um dos provedores públicos de nuvem é uma forma fácil de criar um cluster k8s necessário para esta configuração.A configuração padrão do AKS da Azure é pronto para ser utilizado para a implantação descrita neste artigo.

Criar um novo cluster AKS com 3 nós. Deixe todo o resto padrão.

Figura 5 Criar um cluster AKS

Instale o kubectl em seu computador localmente: https://kubernetes.io/docs/tasks/tools/install-kubectl/

Registre seu cluster AKS com o kubectl local

 

Figura 6 Registre o cluster AKS com kubectl

Depois disto, você pode voltar para o início do artigoe instalar o longhorn e a implantação IRIS.

A instalação no AWS EKS é um pouco mais complicada. Você precisa se certificar que cada instância em seu grupo de nós tem o open-iscsi instalado.

sudo yum install iscsi-initiator-utils -y

Instalar o Longhorn no GKE necessita de um passo extra, descrito aqui: https://longhorn.io/docs/1.0.1/advanced-resources/os-distro-specific/csi-on-gke/

Apêndice B. Instalação Passo a Passo

Passo 1 – Cluster Kubernetes e kubectl

Você precisa um cluster k8s com 3 nós. Apêndice A descreve como conseguir um na Azure.

$ kubectl get nodes
NAME                                STATUS   ROLES   AGE   VERSION
aks-agentpool-29845772-vmss000000   Ready    agent   10d   v1.18.10
aks-agentpool-29845772-vmss000001   Ready    agent   10d   v1.18.10
aks-agentpool-29845772-vmss000002   Ready    agent   10d   v1.18.10

Passo 2 – Instalar o Longhorn

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml

Certifique-se de que todos os pods no namespace ‘longhorn-system’ estão no estado de em execução. Isso pode levar alguns minutos.

$ kubectl get pods -n longhorn-system
NAME                                       READY   STATUS    RESTARTS   AGE
csi-attacher-74db7cf6d9-jgdxq              1/1     Running   0          10d
csi-attacher-74db7cf6d9-l99fs              1/1     Running   1          11d
...
longhorn-manager-flljf                     1/1     Running   2          11d
longhorn-manager-x76n2                     1/1     Running   1          11d
longhorn-ui-df95bdf85-gpnjv                1/1     Running   0          11d

Consulteo guia de instalação do Longhornpara detalhes e solução de problemas https://longhorn.io/docs/1.1.0/deploy/install/install-with-kubectl

Passo 3 – Faça um clone do repositório GitHub

$ git clone https://github.com/antonum/ha-iris-k8s.git
$ cd ha-iris-k8s
$ ls
LICENSE                   iris-deployment.yaml      iris-volume-snapshot.yaml
README.md                 iris-pvc.yaml             longhorn-aws-secret.yaml
iris-cpf-merge.yaml       iris-svc.yaml             tldr.yaml

Passo 4 – implemente e valide os componentes um a um

o arquivo tldr.yaml contém todos os componentes necessários para a implantação em um pacote. Aqui iremos instalá-los um a um e validar a configuração de cada um deles individualmente.

# Se você aplicou o tldr.yaml previamente, apague-o.
$ kubectl delete -f https://github.com/antonum/ha-iris-k8s/raw/main/tldr.yaml

Criar a Requisição de Volume Persistente

$ kubectl apply -f iris-pvc.yaml persistentvolumeclaim/iris-pvc created

$ kubectl get pvc NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE iris-pvc   Bound    pvc-fbfaf5cf-7a75-4073-862e-09f8fd190e49   10Gi       RWO            longhorn       10s

Criar o Mapa de Configuração

$ kubectl apply -f iris-cpf-merge.yaml

$ kubectl describe cm iris-cpf-merge Name:         iris-cpf-merge Namespace:    default Labels:       <none> Annotations:  <none>

Data

merge.cpf:

[config] globals=0,0,800,0,0,0 gmheap=256000 Events:  <none>

criar a implantação iris

$  kubectl apply -f iris-deployment.yaml deployment.apps/iris created

$ kubectl get pods                     NAME                    READY   STATUS              RESTARTS   AGE iris-65dcfd9f97-v2rwn   0/1     ContainerCreating   0          11s

Anote o nome do pod. Você irá utilizá-lo para conectar ao pod no próximo comando

$ kubectl exec -it iris-65dcfd9f97-v2rwn   -- bash

irisowner@iris-65dcfd9f97-v2rwn:~$ iris session iris Node: iris-65dcfd9f97-v2rwn, Instance: IRIS

USER>w $zv IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2020.4 (Build 524U) Thu Oct 22 2020 13:04:25 EDT

h<enter> to exit IRIS shell

exit<enter> to exit pod

acesse os logs do contêiner IRIS

$ kubectl logs iris-65dcfd9f97-v2rwn ... [INFO] ...started InterSystems IRIS instance IRIS 01/18/21-23:09:11:312 (1173) 0 [Utility.Event] Private webserver started on 52773 01/18/21-23:09:11:312 (1173) 0 [Utility.Event] Processing Shadows section (this system as shadow) 01/18/21-23:09:11:321 (1173) 0 [Utility.Event] Processing Monitor section 01/18/21-23:09:11:381 (1323) 0 [Utility.Event] Starting TASKMGR 01/18/21-23:09:11:392 (1324) 0 [Utility.Event] [SYSTEM MONITOR] System Monitor started in %SYS 01/18/21-23:09:11:399 (1173) 0 [Utility.Event] Shard license: 0 01/18/21-23:09:11:778 (1162) 0 [Database.SparseDBExpansion] Expanding capacity of sparse database /external/iris/mgr/iristemp/ by 10 MB.

crie o serviço iris

$ kubectl apply -f iris-svc.yaml    service/iris-svc created

$ kubectl get svc NAME         TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)           AGE iris-svc     LoadBalancer   10.0.214.236   20.62.241.89   52773:30128/TCP   15s

Passo 5 – Acesse o portal de administração

Finalmente – conecte-se ao portal de administração do IRIS, utilizando o IP externo do serviço: http://20.62.241.89:52773/csp/sys/%25CSP.Portal.Home.zen usuário _SYSTEM, senha SYS. Será solicitado que você altere no seu primeiro login.

 

0
0 324
Artigo Eduard Lebedyuk · Nov. 19, 2021 2m read

Recentemente eu precisei gerar uma especificação Swagger a partir de classes persistentes e seriais, então estou publicando meu código (ainda incompleto - você ainda precisa  resolver detalhes específicos do aplicativo mas é um começo). Ele está disponível aqui.

Digamos que você tem estas classes:

2
0 214
Artigo Bob Kuszewski · Maio 20, 2021 5m read

Migrando do Java Business Host para o PEX

Com o lançamento do PEX a partir do InterSystems IRIS 2020.1 e InterSystems IRIS for Health 2020.1, nossos clientes tem agora uma melhor forma de utilizar Java nas Produções de interoperabilidade que através da utilização do Java Business Host. O PEX (Production EXtension) disponibiliza um conjunto completo de APIs para criar componentes de interoperabilidade e está disponível tanto em Java quanto em .NET. O Java Business Host foi descontinuado e será aposentado em versões futuras.

Vantagens do PEX

  • Permite que desenvolvedores criem qualquer componente da Produção de interoperabilidade em Java ou em .NET
  • Estruturas de mensagens mais complexas podem ser enviadas através dos componentes
  • Configurações simplificadas
  • Fluxo de trabalho simplificado , sem utilização de ObjectScript.

O resto deste artigo está focado em como realizar a migração de código existente do Java Business Host para o PEX.

Visão Geral

As classes e interfaces utilizadas pelo PEX são diferentes das do Java Business Host (JBH). Nós iremos disponibilizar uma visão geral das diferenças neste artigo mas a documentação completa te dará maior profundidade sobre o assunto.

Convertendo um Business Service do Java Business Host para o PEX

Para criar um Business Service PEX você precisará implementar a com.intersystems.enslib.pex.BusinessService ao invés da com.intersystems.gateway.bh.BusinessService.

O padrão de design utilizado pelo PEX para Business Service mudou de um onde era esperado que o serviço iniciasse o processo de produção de mensagens para o padrão onde o serviço implementa uma função que é invocada periodicamente para produzir mensagens.

No JBH, seu código seria algo como isso

  @Override
  public boolean OnInit(Production p) throws Exception {
    production = p;

    if (messageThread == null) {
      Messager messager = new Messager();
      messageThread = new Thread(messager);
      messageThread.start();
    }
  
    return true;
  }

No PEX, você precisa apenas implementas três funções

  public void OnInit() throws Exception {
    // Inicialização
    return;
  }

  public Object OnProcessInput(Object messageInput) throws Exception {
    // Aqui é onde você invoca a SendMessage() ou SendMessageAsync()

    return null;
  }

  public void OnTearDown() throws Exception {
    // Desligar
    return;
  }

Você também precisará alterar como as configurações são utilizadas, mensagens são entregues e onde o registro de log é feito. Falaremos mais sobre estas alterações abaixo.

Convertendo um Business Operation do Java Business Host para PEX

Para criar um Business Operation PEX você precisará implementar a com.intersystems.enslib.pex.BusinessOperation ao invés da com.intersystems.gateway.bh.BusinessOperation.

O padrão de design para os Business Operations é estruturalmente o mesmo entre o JBH e o PEX entretanto os parâmetros para os dois principais pontos de entrada forma alterados.

Mudanças no OnInit()

No PEX o OnInit() não recebe parâmetros.

Mudanças no OnMessage()

No PEX o OnMessage() recebe um Object genérico no lugar da String utilizada no JBH. Isto permite que o criador da produção de interoperabilidade envie qualquer tipo de mensagem desejada.

No JBH sua aplicação ficaria mais ou menos algo assim:

  public boolean OnMessage(String message) throws Exception {
    // Lógica de negócio aqui
    return true;
  }

No PEX o parâmetro é um Objeto Java genérico, que você deve instanciar apropriadamente, que permite que você transmita mensagens mais complexas que apenas strings. Aqui está um exemplo de como extrair uma requisição que é do tipo file stream.

  public Object OnMessage(Object request) throws Exception {
    com.intersystems.jdbc.IRISObject streamContainer = (com.intersystems.jdbc.IRISObject)request;
    com.intersystems.jdbc.IRISObject str = (com.intersystems.jdbc.IRISObject)streamContainer.get("Stream");
    String originalFilename = (String)streamContainer.get("OriginalFilename");

    Long contentSize = (Long)str.get("Size");
    String content = (String)str.invoke("Read", contentSize);

    // Lógica de negócio aqui

    return null;
  }

Você também precisará alterar como as configurações são utilizadas, mensagens são entregues e onde o registro de log é feito. Falaremos mais sobre estas alterações abaixo.

Settings

A declaração das configurações também foi simplificada.

No JBH as configurações era declaradas através da string SETTINGS e recuperada através de código, algo como isso:

  String setting = production.GetSetting("Min");
  if (!setting.isEmpty()) {
    min = Integer.parseInt(setting);
  }

No PEX as configurações são apenas campos de membros públicos, desta forma elas são automaticamente carregadas quando a classe é instanciada.

  public int Min = 0;

Qualquer campo de membro público está disponível para ser atribuído em sua produção de interoperabilidade desde que o campo do membro seja um tipo base Java (String, int, etc.).

Mensagens

O envio de Mensagens no PEX é mais poderoso. No JBH mensagens são enviadas como strings. No PEX as mensagens são enviadas como objetos - tanto IRISObject, para objetos definidos em ObjectScript, ou uma subclasse subclass of com.intersystems.enslib.pex.Message, para classes definidas em Java.

No JBH seu código seria algo assim

  production.SendRequest(value.toString());

No PEX seria algo como isso

  MyExampleMessageClass req = new MyExampleMessageClass("mensagem a ser enviada"); 
  SendRequestAsync(Target, req);

Logging

As funções para registro de Logs são todas similares, apenas nomeadas de forma diferente.

No PEX você registraria uma mensagem informativa através da LOGINFO()

  LOGINFO("mensagem recebida");

Gateway de Objetos

O Java Business Host precisava de seu próprio gateway. Com o PEX você pode utilizar um Java gateway apenas para toda sua necessiade de Java. Ou então usar vários, você escolhe. Aqui você encontra uma boa introdução ao gateway.

Conclusão e Feedback

Se você ainda não experimentou utilizar o PEX, o que falta ? O PEX disponibiliza a habilidade de resolver uma quantidade muito mais ampla de problemas de negócio com menos codificação, além de permitir que agora tudo também seja feito em .NET.

Se você tiver dúvidas ou problemas migrando suas aplicações de JBH para PEX, entre em contato conosco pelo WRC.

0
0 104