Pesquisar

Limpar filtro
Anúncio
Angelo Bruno Braga · jan 16, 2023

Conheça Yuxiang Niu - Novo moderador da comunidade de desenvolvedores!

Olá Comunidade! Temos o prazer de dar as boas-vindas a @Niu.Yuxiang como nosso novo moderador na equipe da Comunidade de Desenvolvedores! Vamos cumprimentar @Niu.Yuxiang com muitos aplausos e dar uma olhada em sua biografia! @Niu.Yuxiang é atualmente o líder da equipe clínica do Centro de Informações do Beijing Friendship Hospital, Capital Medical Universit Aqui está uma breve introdução sobre @Niu.Yuxiang: Tenho quase 10 anos de experiência em informatização da área médica. Atualmente lidero uma pequena equipe focada em pesquisa aplicada e desenvolvimento de sistemas de informação hospitalar (Hospital Information System, HIS) baseado no banco de dados Caché. Nossa equipe está familiarizada com HTML, CSS, JavaScript e linguagens de front-end derivadas. Nosso trabalho diário se concentra principalmente no desenvolvimento de funções correspondentes de acordo com as necessidades do usuário e na otimização constante das funções do programa com base nas dificuldades e pontos problemáticos do negócio clínico. Após dois anos de estudo e esforços, nossa equipe concluiu um total de mais de 1.000 novas funções clínicas e requisitos de otimização. Com o desenvolvimento de nosso departamento de TI, nossa força de desenvolvimento se tornará cada vez mais forte, o que pode garantir melhor a resposta oportuna às necessidades clínicas, otimizar e melhorar constantemente os bugs do sistema e melhorar a eficiência do trabalho clínico. Ao mesmo tempo, também atuei como membro da equipe de emergência, responsável pela operação do banco de dados e solução de problemas, para garantir a solução de problemas a tempo. A plataforma de dados da InterSystems é uma excelente plataforma de integração que traz grande comodidade ao nosso negócio com o auxílio desta tecnologia. Também espero que essa excelente tecnologia possa agregar valor para mais unidades irmãs e parceiros. Também espero me comunicar com outras pessoas da comunidade e compartilhar um pouco da minha experiência prática. Ao mesmo tempo, também espero usar esta plataforma para aprender algumas práticas excelentes com você. Vamos crescer e progredir juntos! Obrigado e parabéns, @Niu.Yuxiang! 👏🏼 Espero que você seja um ótimo moderador! Desejamos-lhe uma ótima viagem pela Comunidade de Desenvolvedores!
Artigo
Ron Sweeney · Fev. 10, 2021

API Nativa IRIS para Python na AWS Lambda

Se você está procurando uma maneira inteligente de integrar sua solução IRIS no ecossistema Amazon Web Services, aplicativos sem servidor ou script python baseado em `boto3`, usar a [API Nativa IRIS para Python](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_PYNATIVE) pode ser o caminho a seguir. Até que você precise obter ou definir algo no IRIS, você não tem que ir muito longe com uma implementação em produção para fazer sua aplicação funcionar de um maneira incrível, então, espero que você encontre valor neste artigo e construa algo que seja importante para outros ou somente para você, pois ambos são igualmente válidos. ![imagem](/sites/default/files/inline/images/aws_lambda_native_api_iris_0.png) Se você está procurando algumas justificativas para implementar isso: * Você precisa acertar a trigger de geração de pré-token no Cognito para pesquisar e inserir o contexto de ID do paciente no token para uma solução baseada em SMART on FHIR(R) implementando um fluxo de trabalho com OAUTH2. * Você deseja publicar as configurações de ajuste de provisionamento do IRIS com base no tipo de instância, grupo de nós, toaster ou cluster ECS que você disparou para executar o IRIS no anel zero. * Você quer impressionar a família e os amigos no Zoom com suas habilidades de gerenciamento do IRIS sem que o seu shell saia da AWS cli. ## O ponto Aqui, vamos provisionar uma função lambda da AWS que se comunica com o IRIS e fornecer alguns exemplos sobre como provisioná-la e como interagir com ela em várias capacidades, na esperança de que possamos discutir sobre isso e **publicá-la no pip para tornar as coisas mais fáceis.** ## Com pressa???? ![imagem](/sites/default/files/inline/images/hurry.png) Confira o streaming ## Em todo o caso... Para participar da diversão, você precisará definir algumas coisas em seu plano de voo. ### Rede Você tem o IRIS em execução da maneira que deseja, rodando em uma AWS VPC com exatamente duas sub-redes e um grupo de segurança que permite acesso ao super servidor rodando IRIS... usamos 1972 por motivos nostálgicos e pelo simples fato de que a InterSystems se deu ao trabalho de registrar essa porta no [IANA](https://tools.ietf.org/html/rfc6335), e se você adicionar a nova porta em `/etc/services` sem fazer isso, não é a melhor prática, mas tudo bem. Em nosso caso, é um conjunto de instâncias EC2 espelhadas com verificações de integridade adequadas em torno de um balanceador de carga de rede AWS v2. ![imagem](/sites/default/files/inline/images/toaster2.png) ### Classe de exemplo importada De alguma forma, você conseguiu criar e importar a classe na raiz deste repositório para o namespace `%SYS` em sua instância IRIS. A seguir está um exemplo da classe que gera a saída acima. Se você está se perguntando por que precisamos importar uma classe aqui, consulte a nota abaixo, onde a abordagem recomendada é provisionar algumas classes de wrapper para uso por meio do python. > Nota do Docs: Embora esses métodos também possam ser usados com as classes InterSystems definidas na Biblioteca de Classes, a melhor prática é chamá-las indiretamente, de dentro de uma classe ou rotina definida pelo usuário. Muitos métodos de classe retornam apenas um código de status, passando os resultados reais de volta em um argumento (que não pode ser acessado pela API nativa). As funções definidas pelo sistema (listadas em Funções ObjectScript na Referência ObjectScript) não podem ser chamadas diretamente. Classe de Exemplo: ``` Class ZDEMO.IRIS.Lambda.Operations Extends %Persistent { ClassMethod Version() As %String { Set tSC = 0 Set tVersion = $ZV if ( tVersion '="" ) { set tSC = $$$OK } Set jsonret = {} Set jsonret.status = tSC Set jsonret.payload = tVersion Quit jsonret.%ToJSON() } } ``` Observe acima que decidi trabalhar com base na convenção de sempre retornar um objeto JSON como uma resposta, que também me permite retornar o status e possivelmente preencher a lacuna ao retornar algumas coisas por referência. ### Acesso AWS Obtenha algumas chaves de acesso IAM que permitirão que você provisione e invoque a Função Lambda com a qual iremos mudar o mundo. Verificação antes do voo: ``` IRIS [ $$$OK ] VPC [ $$$OK ] Subnets [ $$$OK ] Security Group [ $$$OK ] IAM Access [ $$$OK ] Imported Class [ $$$OK ] ``` $$$OK, **Vamos lá**. ## Empacotando a API Nativa IRIS para Python para uso na Função Lambda Esta é a parte que seria fantástica se fosse um pacote pip, especialmente se fosse apenas para Linux, já que as funções da AWS Lambda são executadas no BoXenLinux. No momento deste commit, a API não está disponível via pip, mas somos engenhosos e podemos lançar a nossa própria. ``` mkdir iris_native_lambda cd iris_native_lambda wget https://github.com/intersystems/quickstarts-python/raw/master/Solutions/nativeAPI_wheel/irisnative-1.0.0-cp34-abi3-linux_x86_64.whl unzip nativeAPI_wheel/irisnative-1.0.0-cp34-abi3-linux_x86_64.whl ``` Crie `connection.config` Exemplo: [connection.config](https://raw.githubusercontent.com/basenube/iris_native_lambda/main/examples/connection.config) Crie seu manipulador, `index.py` ou use aquele na pasta de exemplos, no [repositório de demonstração no GitHub](https://github.com/basenube/iris_native_lambda). Observe que a versão de demonstração usa variáveis de ambiente e um arquivo externo para as informações de conectividade IRIS. Exemplo: [index.py](https://raw.githubusercontent.com/basenube/iris_native_lambda/main/examples/index.py) Agora compacte-o para uso: ``` zip -r9 ../iris_native_lambda.zip * ``` Crie um bucket S3 e carregue o zip de função nele. ``` cd .. aws s3 mb s3://iris-native-bucket s3 sync iris_native_lambda.zip s3://iris-native-bucket ``` > Isso conclui o empacotamento da API e do manipulador para uso como uma função AWS Lambda. Agora, clique no console para criar a função ou use algo como o Cloudformation para executar o trabalho: ``` IRISAPIFunction: Type: "AWS::Lambda::Function" DependsOn: - IRISSG - VPC Properties: Environment: Variables: IRISHOST: "172.31.0.10" IRISPORT: "1972" NAMESPACE: "%SYS" USERNAME: "intersystems" PASSWORD: "lovetheyneighbor" Code: S3Bucket: iris-native-bucket S3Key: iris_native_lambda.zip Description: "Função API Nativa IRIS para Python" FunctionName: iris-native-lambda Handler: "index.lambda_handler" MemorySize: 128 Role: "arn:aws:iam::8675309:role/BeKindtoOneAnother" Runtime: "python3.7" Timeout: 30 VpcConfig: SubnetIds: - !GetAtt - SubnetPrivate1 - Outputs.SubnetId - !GetAtt - SubnetPrivate2 - Outputs.SubnetId SecurityGroupIds: - !Ref IRISSG ``` Isso foi BASTANTE, mas agora você pode enlouquecer e chamar o IRIS através da função lambda com Python e mudar o mundo. ## Execução! Da forma como o descrito acima é implementado, espera-se que a função seja passada em um objeto de evento que é um tanto estruturado para reutilização, você pode ver a ideia no exemplo de objeto de evento abaixo: ``` { "method": "Version", # importante, se o método não requer argumentos, aplique "none" "args": "none" # exemplo de método com argumentos, separados por vírgulas # "args": "thing1, thing2" } ``` agora você pode, se tiver tolerância para exemplos em linha de comando, dar uma olhada na execução abaixo usando a AWS CLI: ``` (base) sween @ basenube-pop-os ~/Desktop/BASENUBE └─ $ ▶ aws lambda invoke --function-name iris-native-lambda --payload '{"method":"Version","args":"none"}' --invocation-type RequestResponse --cli-binary-format raw-in-base64-out --region us-east-2 --profile default /dev/stdout {{\"status\":1,\"payload\":\"IRIS for UNIX (Red Hat Enterprise Linux for x86-64) 2020.2 (Build 210U) Thu Jun 4 2020 15:48:46 EDT\"}" "StatusCode": 200, "ExecutedVersion": "$LATEST" } ``` Agora, se dermos um passo adiante, a AWS CLI oferece suporte a aliases, então crie um para você mesmo e você pode brincar com total integração com o seu comando aws legal. Aqui está um exemplo de alias cli: ``` └─ $ ▶ cat ~/.aws/cli/alias [toplevel] whoami = sts get-caller-identity iris = !f() { aws lambda invoke \ --function-name iris-native-lambda \ --payload \ "{\"method\":\""${1}"\",\"args\":\"none\"}" \ --invocation-type RequestResponse \ --log-type None \ --cli-binary-format raw-in-base64-out \ gar.json > /dev/null cat gar.json echo echo }; f ``` ...e agora, você pode apenas fazer... ![imagem](/sites/default/files/inline/images/aws_lambda_iris_python_0.png) Se cuide! – Argumentos técnicos são bem-vindos! Ótimo trabalho, estava curioso sobre essa comunicação de Iris, Python e AWS.
Artigo
Henrique Dias · Abr. 21, 2021

Você já conhece o ZPM Explorer?

Fala galera, @José.Pereira e eu queremos falar sobre nosso novo projeto, ZPM Explorer, é uma interface gráfica para explorar e descobrir as grandes aplicações que estão disponíveis no InterSystems Package Manager. ## A ideia A ideia do ZPM Explorer é deixar a vida de todos mais fácil quando procurarem por aplicações que são oferecidas pelo ZPM. A cada dia mais e mais aplicações se juntam ao universo ZPM, então, porque não ajudar desenvolvedores e não desenvolvedores a tirarem proveito deste incrível universo? ## A aplicação ZPM é uma aplicação simples e poderosa, para isso tentamos traduzir a simplicidade em algo simples de usar e poderosa na forma de pesquisar, facilitando a vida das pessoas na hora de encontrar a solução ideal com um simples clique. A página inicial do ZPM Explorer é uma tabela com os dados fornecidos pelo endpoint [https://pm.community.intersystems.com/packages/-/all](https://pm.community.intersystems.com/packages/-/all) Com os seguintes campos: - Name: nome da aplicação - Description: descrição do que a aplicação faz - Repository: link para o repositório Github - Version: versão atual da aplicação hospedada no Package Manager ![](https://raw.githubusercontent.com/diashenrique/zpm-explorer/master/images/zpmexplorer.png) ## Instalando novas aplicações O uso da aplicação é simples, rápido e objetivo. 1. Pesquisa a aplicação desejada 2. Seleciona a aplicação 3. Clique no botão "Install" 4. Confirme se desejar instalar 5. Pronto 6. Agora é só correr para o abraço e tirar proveito da nova solução instalada ## Gerenciando pacotes instalados ![](https://raw.githubusercontent.com/diashenrique/zpm-explorer/master/images/installedApps.png) ZPM Explorer também oferece uma página para você fazer o gerenciamento das aplicações existentes, instaladas através do ZPM. Nessa página você pode atualizar, desinstalar e até mesmo usar um "wizard" para faciitar sua vida na hora de criar seu module.xml e mencionar as aplicações desejadas como dependentes. ![](https://raw.githubusercontent.com/diashenrique/zpm-explorer/master/images/export.png) ## Demo [https://zpm-explorer.contest.community.intersystems.com/csp/irisapp/explorer.html](https://zpm-explorer.contest.community.intersystems.com/csp/irisapp/explorer.html) Se você curtiu o aplicativo e acredita que merecemos seu voto, por favor, vote em **zpm-explorer**! https://openexchange.intersystems.com/contest/current ![](https://media.giphy.com/media/1jY41jR11D3xhZxGUv/giphy.gif)
Artigo
Henrique Dias · Fev. 9, 2023

iris-tripleslash - vamos detonar geral

Fala galera, beleza? iiii lá vamos nós. Ano novo, nova competição, novo projeto, velhos motivos. Triple Slash na área! Aprendi o meu primeiro if, hello world, em 1999. Ainda lembro do meu professor tentando explicar para turma toda como um simples "while" funcionava para descobrir se uma determinada condição havia sido atingida. @Renato.Banzai ainda lembra do professor Barbosa tentando chegar a porta na explicação "passo-a-passo"? De lá pra cá, sempre amei a ideia de programar, criar coisas, transformar ideias em projetos, em coisas úteis. Mas para criar algo, você precisa ter certeza de que isso funciona. Não apenas sair fazendo coisas novas, mas garantir que o que você criou funciona, mesmo adicionando novas funcionalidades. E sendo super transparente, eu acho a parte de testes chata demais! Imagina uma parada chata, é o que teste é pra mim. Se você curte essas paradas, nada contra, mas não é minha praia. Comparando mal e porcamente, seria como limpar a casa. Todo mundo curte um ambiente limpinho, mas limpar a casa, passar roupa, etc é uma baita chatice. Com isso em mente, pensamos em facilitar a vida de todo desenvolvedor na hora de testar suas aplicações. Inspirando no estilo do elixir e nessa ideia da InterSystems Ideas (Valeu @Evgeny.Shvarov)! Nós tentamos melhorar o processo de testes e torná-lo mais fácil e agradável de se fazer. Simplificamos o %UnitTest e para mostrar como utilizar o TripleSlash para criar seus testes unitários, se liga no exemplo abaixo: Vamos supor que você tenha a seguinte classe e método e queira escrever um teste unitário: Class dc.sample.ObjectScript { ClassMethod TheAnswerForEverything() As %Integer { Set a = 42 Write "Hello World!",! Write "This is InterSystems IRIS with version ",$zv,! Write "Current time is: "_$zdt($h,2) Return a } } Como podemos ver o método TheAnswerForEverything() apenas retorna o número 42. Então, vamos documentar o método e como o TripleSlash deve criar o teste unitário: /// A simple method for testing purpose. /// /// <example> /// Write ##class(dc.sample.ObjectScript).Test() /// 42 /// </example> ClassMethod TheAnswerForEverything() As %Integer { ... } Testes unitários devem estar entre a tag <example></example>. Você pode colocar todo o tipo de documentação, mas todos os testes devem estar obrigatoriamente dentro da tag. Agora, vamos iniciar uma sessão no IRIS, ir para o Namespace IRISAPP, criar uma instância da classe Core passando o nome da classe (ou o nome do pacote de classes para todas elas) e executar o método Execute() : USER>ZN "IRISAPP" IRISAPP>Do ##class(iris.tripleSlash.Core).%New("dc.sample.ObjectScript").Execute() TripleSlash vai interpretar mais ou menos como "Dado o resultado do método Test(), afirmamos que é igual a 42". Então, a nova classe será criada: Class iris.tripleSlash.tst.ObjectScript Extends %UnitTest.TestCase { Method TestTheAnswerForEverything() { Do $$$AssertEquals(##class(dc.sample.ObjectScript).TheAnswerForEverything(), 42) } } Agora vamos adicionar um novo método para testar outras coisas e falar para o TripleSlash como escrever esses testes. Class dc.sample.ObjectScript { ClassMethod GuessTheNumber(pNumber As %Integer) As %Status { Set st = $$$OK Set theAnswerForEveryThing = 42 Try { Throw:(pNumber '= theAnswerForEveryThing) ##class(%Exception.StatusException).%New("Sorry, wrong number...") } Catch(e) { Set st = e.AsStatus() } Return st } } Como podem ver, o método GuessTheNumber() espera um número, retorna um $$$OK apenas quando o número 42 é passado e devolve um erro para qualquer outro valor. Então vamos falar como queremos que o TripleSlash crie o teste unitário: /// Another simple method for testing purpose. /// /// <example> /// Do ##class(dc.sample.ObjectScript).GuessTheNumber(42) /// $$$OK /// Do ##class(dc.sample.ObjectScript).GuessTheNumber(23) /// $$$NotOK /// </example> ClassMethod GuessTheNumber(pNumber As %Integer) As %Status { ... } Executando novamente o método Execute() e verá um novo método de teste na sua classe de teste iris.tripleSlash.tst.ObjectScript: Class iris.tripleSlash.tst.ObjectScript Extends %UnitTest.TestCase { Method TestGuessTheNumber() { Do $$$AssertStatusOK(##class(dc.sample.ObjectScript).GuessTheNumber(42)) Do $$$AssertStatusNotOK(##class(dc.sample.ObjectScript).GuessTheNumber(23)) } } Atualmente temos suporte para: $$$AssertStatusOK, $$$AssertStatusNotOK and $$$AssertEquals. TripleSlash nos permite gerar testes a partir de exemplos de códigos encontrados na documentação dos métodos. Isso ajuda a matar 2 coelhos com uma cajadada só, melhorando sua documentação de classe e criando um teste unitário. Agradecimentos Uma vez mais, queremos agradecer a todos que vem nos dando apoio na comunidade com as aplicações que criamos. Se você achou nosso aplicativo interessante, pensa com carinho para votar em iris-tripleslash e nos ajude a continuar contribuindo para o crescimento da comunidade a e aseguir nesse caminho!
Artigo
Andre Larsen Barbosa · Jul. 14, 2021

Aprimoramentos JSON

O InterSystems IRIS 2019.1 já foi lançado há algum tempo e gostaria de abordar algumas melhorias para lidar com JSON que podem ter passado despercebidas. Lidar com JSON como um formato de serialização é uma parte importante da construção de aplicativos modernos, especialmente ao interagir com terminais REST. Formatando JSON Em primeiro lugar, ajuda se você pode formatar JSON para torná-lo mais legível. Isso é muito útil quando você precisa depurar seu código e observar o conteúdo JSON de um determinado tamanho. Estruturas simples são fáceis de procurar por um humano, mas assim que você tiver vários elementos aninhados, pode ficar complicado com bastante facilidade. Aqui está um exemplo simples: {"name":"Gobi","type":"desert","location":{"continent":"Asia","countries":["China","Mongolia"]},"dimensions":{"length":1500,"length_unit":"km","width":800,"width_unit":"km"}} Um formato mais legível torna mais fácil explorar a estrutura do conteúdo. Vamos dar uma olhada na mesma estrutura JSON, mas desta vez com quebras de linha e recuo adequados: { "name":"Gobi", "type":"desert", "location":{ "continent":"Asia", "countries":[ "China", "Mongolia" ] }, "dimensions":{ "length":1500, "length_unit":"km", "width":800, "width_unit":"km" } } Mesmo este exemplo simples aumenta um pouco a saída, então você pode ver por que este não é o padrão em muitos sistemas. Mas com essa formatação detalhada, você pode identificar subestruturas facilmente e ter uma noção se algo está errado. InterSystems IRIS 2019.1 introduziu um pacote com o nome %JSON. Você pode encontrar alguns utilitários úteis aqui, sendo um formatador, que permite que você obtenha exatamente o que viu acima: Formate seus objetos dinâmicos e matrizes e strings JSON em uma representação mais legível. %JSON.Formatter é uma classe com uma interface muito simples. Todos os métodos são métodos de instância, então você sempre começa recuperando uma instância. USER>set formatter = ##class(%JSON.Formatter).%New() A razão por trás dessa escolha é que você pode configurar seu formatador para usar certos caracteres para o recuo (por exemplo, espaços em branco x tabulações) e terminadores de linha uma vez e usá-los sempre que precisar. O método Format() pega um objeto / array dinâmico ou uma string JSON. Vejamos um exemplo simples usando um objeto dinâmico: USER>do formatter.Format({"type":"string"}) { "type":"string" } E aqui está um exemplo com o mesmo conteúdo JSON, mas desta vez representado como uma string JSON: USER>do formatter.Format("{""type"":""string""}") { "type":"string" } O método Format() envia a string formatada para o dispositivo atual, mas você também verá os métodos FormatToString() e FormatToStream() caso queira direcionar a saída para uma variável. Mudando a marcha O texto acima é bom, mas pode não valer um artigo por si só. O InterSystems IRIS 2019.1 também apresenta uma maneira de serializar objetos persistentes e transitórios de e para JSON. A classe que você deseja examinar é%JSON.Adaptor. O conceito é muito semelhante a% XML.Adaptor, daí o nome. Qualquer classe que você gostaria de serializar de e para JSON precisa ter a subclasse%JSON.Adaptor. A classe herdará alguns métodos úteis, os mais notáveis são %JSONImport() e %JSONExport(). É melhor demonstrar isso com um exemplo. Suponha que temos as seguintes classes: Class Model.Event Extends (%Persistent, %JSON.Adaptor) { Property Name As %String; Property Location As Model.Location; } e Class Model.Location Extends (%Persistent, %JSON.Adaptor) { Property City As %String; Property Country As %String; } Como você pode ver, temos uma classe de evento persistente, que se vincula a um local. Ambas as classes herdam de %JSON.Adaptor. Isso nos permite preencher um gráfico de objeto e exportá-lo diretamente como uma string JSON: USER>set event = ##class(Model.Event).%New() USER>set event.Name = "Global Summit" USER>set location = ##class(Model.Location).%New() USER>set location.City = "Boston" USER>set location.Country = "United States of America" USER>set event.Location = location USER>do event.%JSONExport() {"Name":"Global Summit","Location":{"City":"Boston","Country":"United States of America"}} Claro, você também pode ir na outra direção com %JSONImport(): USER>set jsonEvent = {"Name":"Global Summit","Location":{"City":"Boston","Country":"United States of America"}} USER>set event = ##class(Model.Event).%New() USER>do event.%JSONImport(jsonEvent) USER>write event.Name Global Summit USER>write event.Location.City Boston Os métodos de importação e exportação funcionam para estruturas aninhadas arbitrariamente. Semelhante ao %XML.Adaptor, você pode especificar a lógica de mapeamento para cada propriedade individual definindo os parâmetros correspondentes. Vamos mudar a classe Model.Event para a seguinte definição: Class Model.Event Extends (%Persistent, %JSON.Adaptor) { Property Name As %String(%JSONFIELDNAME = "eventName"); Property Location As Model.Location(%JSONINCLUDE = "INPUTONLY"); } Supondo que temos a mesma estrutura de objeto atribuída ao evento variável como no exemplo acima, uma chamada para %JSONExport () retornaria o seguinte resultado: USER>do event.%JSONExport() {"eventName":"Global Summit"} O nome da propriedade é mapeado para o nome do campo eventName e a propriedade Location é excluída da chamada %JSONExport(), mas será preenchida quando presente no conteúdo JSON durante uma chamada %JSONImport(). Existem vários parâmetros disponíveis para permitir que você ajuste o mapeamento: %JSONFIELDNAME corresponde ao nome do campo no conteúdo JSON. %JSONIGNORENULL permite que o desenvolvedor substitua o tratamento padrão de strings vazias para propriedades de string. %JSONINCLUDE controla se essa propriedade será incluída na saída / entrada JSON. If %JSONNULL for verdadeiro (= 1), as propriedades não especificadas serão exportadas como o valor nulo. Caso contrário, o campo correspondente à propriedade é apenas ignorado durante a exportação. %JSONREFERENCE especifica como as referências do objeto são tratadas. "OBJECT" é o padrão e indica que as propriedades da classe referenciada são usadas para representar o objeto referenciado. Outras opções são "ID", "OID" e "GUID". Isso fornece um alto nível de controle e é muito útil. Já se foi o tempo de mapear manualmente seus objetos para JSON. Mais uma coisa Em vez de definir os parâmetros de mapeamento no nível da propriedade, você também pode definir um mapeamento JSON em um bloco XData. O seguinte bloco XData com o nome OnlyLowercaseTopLevel tem as mesmas configurações de nossa classe de evento acima. Class Model.Event Extends (%Persistent, %JSON.Adaptor) { Property Name As %String; Property Location As Model.Location; XData OnlyLowercaseTopLevel { <Mapping xmlns="http://www.intersystems.com/jsonmapping"> <Property Name="Name" FieldName="eventName"/> <Property Name="Location" Include="INPUTONLY"/> </Mapping> } } Há uma diferença importante: os mapeamentos JSON em blocos XData não alteram o comportamento padrão, mas você deve referenciá-los nas chamadas %JSONImport() e %JSONExport() correspondentes como o último argumento, por exemplo: USER>do event.%JSONExport("OnlyLowercaseTopLevel") {"eventName":"Global Summit"} Se não houver bloco XData com o nome fornecido, o mapeamento padrão será usado. Com essa abordagem, você pode configurar vários mapeamentos e fazer referência ao mapeamento necessário para cada chamada individualmente, concedendo ainda mais controle e tornando seus mapeamentos mais flexíveis e reutilizáveis. Espero que essas melhorias facilitem sua vida e aguardo seu feedback. Deixe-me saber o que você pensa nos comentários.
Artigo
Heloisa Paiva · Maio 26, 2023

Facilitando a análise da memória ocupada pelas tabelas

Introdução Dentre as diversas soluções que desenvolvemos aqui na Innovatium, um desafio comum é a necessidade de acesso ao tamanho das bases de dados. Entretanto, notei que isso não é algo tão trivial no IRIS. Esse tipo de informação é importante para manter um controle do fluxo de dados e do custo em GB's de um sistema a ser implementado. Contudo, o que realmente me chamou atenção é a necessidade dela para uma função muito importante: migrar para cloud. Afinal, quem não quer migrar seus sistemas para cloud hoje em dia, certo? Os serviços de cloud oferecem tudo que um sistema precisa de maneira descomplicada: mirroring, escalabilidade, proteção dos dados, facilidade de fluxo, e o que faz toda pessoa jurídica se apaixonar: é pago pelo uso. E ainda mais, com as gigantescas Google (Cloud), Microsoft (Azure), Amazon (AWS), etc. oferecendo seus serviços quase impecáveis a preços acessíveis, é algo que com um pouco de investimento pode ser uma realidade para qualquer um que queira aumentar seus lucros e economizar a longo prazo. Além do mais, para quem já está aqui, a própria InterSystems tem seus serviços de Cloud também. Por essa razão venho aqui apresentar o app que estou desenvolvendo, no qual não é só possível, mas também é fácil observar tamanhos das globais, para que as análises necessárias para obter um serviço em cloud seja apenas tão complicada quanto o seu provedor favorito a complique. Inspiração Me inspirando nas aplicações isc-global-size-tracing e globals-tool, estou criando uma versão que possa unir o que há de melhor nas duas e acrescentar adaptações necessárias para o nosso negócio. Mas antes de mostrar meu desenvolvimento, vou apresentar brevemente as aplicações inspiradas. A isc-global-size-tracing oferece serviços de análises a partir de classes dentro do próprio Iris, com métodos mais amigáveis ao usuário e opções de tasks scheduladas que atualizam uma tabela com vários dados sobre as globais. Há também opções prontas de exportação das informações para arquivos externos. Assim, se já existe uma familiaridade com Object Script não é tão difícil tirar alguns minutos para entender o seu funcionamento e adaptar ao seu negócio. Já a globals-tool mostra um portal em forma de website onde é possível checar os tamanhos alocados e os tamanhos disponíveis para cada global, dentro de seus namespaces. É um pouco mais simples, porém mais amigável ao usuário, podendo ser utilizada também para disponibilizar os dados para pessoas de outras áreas sem conhecimento algum em programação. Mudanças e adaptações podem exigir conhecimento prévio não somente em Object Script, mas também em React e similares. O que eu gostaria então é de trazer as várias opções da primeira com a usabilidade da segunda, além de adicionar outras opções de análises e exportações. O App - o que já está disponível Nesta sessão, vou explicar um pouco do que já foi feito e como pode ser aproveitado por você e sua empresa. Todo o código está disponível para consulta, clone ou download no meu Github. Para começar a utilizar é muito simples, basta clonar ou fazer download do repositório na pasta que preferir e configurar para a sua instância do IRIS. Abra o terminal na pasta onde deseja clonar o repositório e use o comando git clone https://github.com/heloisatambara/iris-size-django Entre na pasta iris-size-django e instale os requisitos necessários: .../iris-size-django > pip install -r requirements.txt Edite o arquivo .../iris-size-django/globalsize/settings.py para personalizar as configurações da base de dados. Não mude o parâmetro ENGINE, ele deve apontar para a aplicação de CaretDev, django-iris. Contudo, altere o NAME para o namespace, USER e PASSWORD para um usuário com privilégios adequados (é necessário acesso ao namespace %SYS e poder criar uma tabela no namespace desejado) e os parâmetros HOST e PORT devem direcionar à sua instância. De volta ao terminal, vamos rodar os comandos makemigrations para preparar o app, migrate para criar a tabela onde vamos armazenar as informações das globais e runserver para colocar tudo em prática. > python manage.py makemigrations > python manage.py migrate > python manage.py runserver Agora, é só abrir o link http://127.0.0.1:8000/globals/ no seu navegador preferido e clicar em update. Em poucos segundos você deve ter uma tabela com todos os namespaces e suas respectivas globais, mostrando a quantidade (em MB) de memória alocada e utilizada, como mostra a imagem no início da sessão. A instância a ser analizada está em globals/api/methods.py, e não precisa ser necessariamente a mesma em que definimos em DATABASES, em settings.py. Para mais detalhes sobre esse tipo de conexão, você pode ler a documentação sobre InterSystems IRIS Cloud SQL ou os tutoriais Python e IRIS na prática com exemplos (na sessão ObjectScript no ambiente Python) ou Retornando valores com Python. Agora vamos dar uma olhada melhor na parte de cima da foto: Aqui, podemos ver as opções de filtros, exportação e ordenação. Você pode digitar parte do nome da base de dados ou das globais para ver resultados específicos, ou digitar um número positivo em Size ou Allocated para ver resultados acima daquele valor. Se digitar um número negativo, verá os resultados abaixo do módulo do valor. Clique no botão Filter para efetivar o filtro. Selecione o modelo de exportação (CSV, XML, JSON) e clique em Export para exportar para a pasta iris-size-django. Lembrando que os filtros aplicados serão refletidos na exportação. Além disso, você pode mudar o endereço de exportação no código, em .../iris-size-django/globals/views.py.> Por fim, você pode selecionar ordenação crescente em ordem alfabética pelo nome da base de dados e da global ou pelo tamanho ocupado ou quantidade alocada. Clique no botão Filter para efetivar a ordenação e os filtros digitados. Obs.: A ordenação não será refletida na exportação. No final da página você pode ver a contagem de globais dentro dos filtros selecionados, além da quantidade total alocada e utilizada: Se você quiser fazer análises mais profundas ou até mesmo ver a tabela original, uma opção boa é entrar no portal de administração da instância referida em settings.py, na sessão do SQL e selecionar o namespace referido no mesmo local. A tabela terá sido criada automaticamente pelo Django com o nome de SQLUser.globals_iglobal, e ali você pode usar as ferramentas da InterSystems para executar todo tipo de query. Obs.: em settings, o parâmetro DEBUG está marcado como TRUE pois ainda está em desenvolvimento. Ideias futuras Minhas primeiras ideias são trazer mais funções para o portal. Atualmente é possível alterar configurações de exportação e da base de dados diretamente no código, além de fazer queries mais complexas pelo portal do IRIS. Contudo, acredito que unificar tudo isso no portal será mais eficiente. Além disso, também estou estudando para acrescentar um acompanhamento do fluxo de dados por período. Por fim, gostaria de ouvir de você: acha que esse tipo de aplicação pode ajudar seu negócio? Que outras funções você gostaria de ver aqui? Gostaria de ver alguma função já existente do IRIS de maneira mais amigável? Ou gostaria que algo apresentado aqui fosse mais simplificado?
Pergunta
Jullyanna Mendes · Dez. 22, 2020

iKnow

Boa tarde, estou desenvolvimento uma demo com iKnow, e gostaria de saber como eu acesso dados do healthshare? Tudo bem Jullyanna? Que tipo de informação não estruturada você pretende recuperar do HealthShare ? Você consegue me explicar um pouco mais sobre a demo que você tem em mente ? Obrigado. Boa tarde, basicamente seria pegar o acessos dos pacientes oncológicos e identificar as possibilidades de ser avançado, iniciante ou mediano. Uma forma de prevenir e antecipar os tratamentos. bom dia Jullyanna, entendo que esta informação deva estar em algum laudo de exame carregado no HealthShare, correto? portanto deve estar dentro do SDA, de onde podemos extrair e utilizar o NLP(iKnow) analisar semanticamente o conteúdo. Você já definou os conceitos que indicaram o estado do evento? avançado, iniciante ou mediano, já que teremos que entender que conceitos indicam os estados que pretendemos avaliar. Se você quiser podemos marcar uma conversa para entender melhor suas necessidades. Olá Jullyanna. Como cliente você pode acessar tanto a documentação do produto como os treinamentos online, seja para o HealthShare ou para o iKnow. Assim como o Rochael, me coloco também a disposição para uma conversa para entendermos melhor a sua necessidade. Obrigado. Boa tarde, o SDA ele está transmitindo o binário do PDF. Dentro do healthshare o documento ta em formado pdf. bom dia Jullyanna, neste caso teremos que montar uma alternativa para extrair o conteúdo do PDF. Podemos marcar uma conversa na semana que vem para tratarmos do assunto? obrigado e feliz natal Oi Juliana, tudo bem? Você já viu aplicação do @Yuri.Gomes no OpenExchange? https://openexchange.intersystems.com/package/OCR-Service Na descrição da aplicação você tem a seguinte informação:InterSystems IRIS Interoperability OCR ServiceThis is an InterSystems IRIS Interoperability OCR Service to extract text from images and pdfs from a file into a multipart request from form or http request. What The the service doesThis application receive a http multipart request with a file, extract text using OCR from Tesseract and returns the result Também tem um video que ele fez demonstrando um pouco mais. https://www.youtube.com/watch?v=E8MHJ0kAdbk Espero que possa ajudar. Abraços
Pergunta
Alexandre Lago · Jun. 21, 2022

Contar a palavra com maior número de caracteres

Olá, comecei a trabalhar com Caché a pouco, e estou em treinamento. Me surgiu uma dúvida de uma determinada atividade, aonde a regra solicita que o usuário digite uma string, e selecione uma das opções listradas, e uma delas e informar a palavra com maior número de carácteres da string. Já tentei de tudo, porém não consegui chegar a nenhuma conclusão. Desde já agradeço Olá Alexandre,Não entendi muito bem, mas, você já fez a contagem de caracteres da string que o usuário digitou? Se não de uma olhada na função $Length https://docs.intersystems.com/ens201815/csp/docbook/Doc.View.cls?KEY=RCOS_flength Oi Alexandre! O que me veio em mente rapidamente foi criar um código que transforme a sua string/frase em uma lista de palavras para depois percorrer a lista contando o numero de letras de cada palavra da lista. Algo assim: Set frase = "Como contar a palavra com maior numero de caracteres" #; cria uma lista da string com delimitador " " espaço Set fraseList = $Listfromstring(frase," ") #; percorre a lista e imprime a posição da palavra na frase (i), o tamanho da palavra ($length) e a palavra ($listget(fraseList,i))For i=1:1:$Listlength(fraseList) w !,i_"- tamanho:"_$length($listget(fraseList,i))_"->"_$lg(fraseList,i) O código acima pode ser executado no Terminal. Mas se você somente desejar saber o maior tamanho, basta salvar o tamanho em uma variável comparando os tamanhos. Exemplo: Set maiorTamanho=""For i=1:1:$Listlength(fraseList) { set tamanho=$length($listget(fraseList,i)) if tamanho>maiorTamanho { set maiorTamanho=tamanho set maiorPalavra=$listget(fraseList,i) }} Write !,maiorPalavra_" - tamanho: "_maiorTamanho Espero que ajude! :-) MAIORPALAVRA ;Verifica qual é a maior palavra da frase Set Frase="O Cache da InterSystems é Imbativel" Write !,"Frase : ",Frase,! ; Escreve Set qp=$Length(Frase," ") ; Conta as palavras da frase Set (qtl,mqtl)=0 ; Zera os contadores For pal=1:1:qp { ; comando For Set palavra=$Piece(Frase," ",pal) ; percorre as palavras Set qtl=$L(palavra) ; Verifica tamanho da palavra If qtl>mqtl Set mqtl=qtl,pi=pal ; Define a maior palavra } Write !,"A maior palavra da frase é ",$Piece(Frase," ",pi),! ; Escreve a maior palavra ; ; Crie um programa COS com os comandos acima e execute no terminal
Artigo
Angelo Bruno Braga · Fev. 25, 2022

Implantações IRIS com Alta disponibilidade no Kubernetes sem utilizar espelhamento

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 objetos, automaticamente 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.
Artigo
Gabriel Vellasques Tureck · Mar. 22, 2021

Proteja sua API REST aplicando OWASP Top 10

Olá comunidade, Você sabia sobre OWASP e os dez principais riscos de segurança de aplicativos da Web para sua API da Web ou aplicativos da Web? OWASP é uma fundação comunitária criada para nos ajudar a melhorar a segurança de aplicativos / APIs da web. O OWASP torna os aplicativos da web mais seguros por meio de seus projetos de software de código aberto liderados pela comunidade, centenas de capítulos em todo o mundo, dezenas de milhares de membros e hospedando conferências locais e globais. Para resumir os principais procedimentos para tornar seu aplicativo da web / API da web mais seguro, o OWASP publicou as recomendações "Top 10 Web Application Security Risks" (fonte: https://owasp.org/www-project-top-ten/): 1- Injection.. Falhas de injeção, como injeção de SQL, NoSQL, OS e LDAP, ocorrem quando dados não confiáveis ​​são enviados a um intérprete como parte de um comando ou consulta. Os dados hostis do invasor podem induzir o intérprete a executar comandos indesejados ou acessar dados sem a autorização adequada.2- Broken Authentication.. As funções de aplicativo relacionadas à autenticação e gerenciamento de sessão são frequentemente implementadas incorretamente, permitindo que os invasores comprometam senhas, chaves ou tokens de sessão ou explorem outras falhas de implementação para assumir as identidades de outros usuários temporária ou permanentemente.3- Sensitive Data Exposure. Muitos aplicativos da web e APIs não protegem adequadamente dados confidenciais, como finanças, saúde e PII. Os invasores podem roubar ou modificar esses dados fracamente protegidos para conduzir fraude de cartão de crédito, roubo de identidade ou outros crimes. Os dados confidenciais podem ser comprometidos sem proteção extra, como criptografia em repouso ou em trânsito, e requerem precauções especiais quando trocados com o navegador.4- XML External Entities (XXE). Muitos processadores XML mais antigos ou mal configurados avaliam referências de entidades externas em documentos XML. Entidades externas podem ser usadas para divulgar arquivos internos usando o manipulador de URI de arquivo, compartilhamentos de arquivos internos, varredura de porta interna, execução remota de código e ataques de negação de serviço.5- Broken Access Control. As restrições sobre o que os usuários autenticados têm permissão para fazer muitas vezes não são aplicadas de forma adequada. Os invasores podem explorar essas falhas para acessar funcionalidades e / ou dados não autorizados, como acessar contas de outros usuários, visualizar arquivos confidenciais, modificar dados de outros usuários, alterar direitos de acesso, etc.6- Security Misconfiguration. A configuração incorreta de segurança é o problema mais comum. Isso geralmente é o resultado de configurações padrão inseguras, configurações incompletas ou ad hoc, armazenamento em nuvem aberta, cabeçalhos HTTP configurados incorretamente e mensagens de erro detalhadas contendo informações confidenciais. Não apenas todos os sistemas operacionais, estruturas, bibliotecas e aplicativos devem ser configurados com segurança, mas também devem ser corrigidos / atualizados em tempo hábil.7- Cross-Site Scripting (XSS). As falhas de XSS ocorrem sempre que um aplicativo inclui dados não confiáveis ​​em uma nova página da web sem validação ou escape adequado, ou atualiza uma página da web existente com dados fornecidos pelo usuário usando uma API do navegador que pode criar HTML ou JavaScript. O XSS permite que os invasores executem scripts no navegador da vítima, que podem sequestrar as sessões do usuário, desfigurar sites ou redirecionar o usuário para sites maliciosos.8- Insecure Deserialization. A desserialização insegura geralmente leva à execução remota de código. Mesmo que as falhas de desserialização não resultem na execução remota de código, elas podem ser usadas para realizar ataques, incluindo ataques de repetição, ataques de injeção e ataques de escalonamento de privilégios.9- Using Components with Known Vulnerabilities. Componentes, como bibliotecas, estruturas e outros módulos de software, são executados com os mesmos privilégios do aplicativo. Se um componente vulnerável for explorado, esse tipo de ataque pode facilitar a perda séria de dados ou o controle do servidor. Aplicativos e APIs que usam componentes com vulnerabilidades conhecidas podem minar as defesas do aplicativo e permitir vários ataques e impactos.10- Insufficient Logging & Monitoring. O registro e o monitoramento insuficientes, juntamente com a integração ausente ou ineficaz com a resposta a incidentes, permitem que os invasores ataquem ainda mais os sistemas, mantenham a persistência, se movam para mais sistemas e adulterem, extraiam ou destruam dados. A maioria dos estudos de violação mostra que o tempo para detectar uma violação é de mais de 200 dias, normalmente detectado por partes externas em vez de processos internos ou monitoramento. Algumas técnicas podem ser usadas para implementar os dez primeiros OWASP, consulte a tabela: Recursos de recomendação OWASP Recursos Injection No SQL, use parâmetros de entrada especificados usando o “?” caractere ou variáveis ​​de host de entrada (por exemplo,: var). Evite concatenar instruções SQL e argumentos de método de entrada.Use a API Sanitazer como https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API Broken Authentication Crie senhas fortes, consulte o documento da Microsoft: https://support.microsoft.com/en-us/windows/create-and-use-strong-passwords-c5cebb49-8c53-4f5e-2bc4-fe357ca048eb Não use senhas dentro do código-fonte, criptografe-o, use serviços de cofre ou serviços SSO. Externalize suas senhas usando parâmetros do ambiente Docker / OS Não permita ataques de força bruta usando gateways de API como IAM: https://docs.intersystems.com/components/csp/docbook/Doc.View.cls?KEY=CIAM1.5 Sensitive Data Exposure Exposição de dados confidenciais Evite retornar dados de cartão de crédito, dados de saúde e outros dados confidenciais em sua API, se não for possível, criptografe os canais de mensagens e o armazenamento de dados confidenciais. Minimize a coleta de dados ao mínimo possível. XXE XXE Use% XMLAdaptor Broken Access Control Use ferramentas de gerenciamento de acesso como IAM: https://docs.intersystems.com/components/csp/docbook/Doc.View.cls?KEY=CIAM1.5 Security Misconfiguration Atualize seu software periodicamente e execute o software Pentest em seu ambiente para realizar os procedimentos apropriados. Siga o Guia de administração de segurança da intersystems: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCAS XSS Faça a sanitização / validação de entrada, consulte dicas OWASP: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html Insecure deserialization Crie hash para arquivos, crie pastas mais seguras sem permissão de execução para armazenar arquivos e validar extensões de arquivos Using Components with Known Vulnerabilities Na pilha da InterSystems o Apache Web Server é a ferramenta mais conhecida, portanto tome cuidado ao configurá-la para a produção, seguindo: https://www.tecmint.com/apache-security-tips/. Habilite o firewall do seu sistema operacional para ubuntu executar ufw enable (consulte: https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu-18-04 ) Insufficient Logging & Monitoring Use o Log Monitor (https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_MONITOR) Siga-o: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=ALOG Monitore usando SAM: https://docs.intersystems.com/sam/csp/docbook/DocBook.UI.Page.cls?KEY=ASAM Você pode usar o software WAF em alinhamento com os dez principais OWASP, consulte: https://www.g2.com/categories/api-security ou use o IAM da InterSystems. Da lista G2, gosto do 42 crunch, que permite uma conta gratuita e você indica seu arquivo OpenAPI e ele é analisado para relatar recomendações, veja em https://42crunch.com/owasp-api-security-top-10/.
Artigo
Yuri Marx · jan 25, 2021

Geradores de Documentação Estática

Olá comunidade, No passado, a documentação técnica do código-fonte e dos produtos de software era gerada em chm, arquivos pdf e geradores de documentação das próprias linguagens de programação. Essa abordagem antiga tinha as seguintes limitações:1. Documentação desatualizada;2. Documentação não interativa e de difícil consulta;3. Layout sem resposta, não amigável e não aderente ao HTML;4. Incapacidade de customizar o layout da documentação;5. Incapacidade de ter documentação HTML 5 online e offline.6. Falta de suporte de Markdown. Hoje, existem várias soluções de geração de documentação que produzem Portais de Documentação Web muito atrativos, interativos, responsivos e com opções estáticas e dinâmicas, com suporte total para HTML 5 e mais recentemente Markdown. Veja a tabela com as opções de código aberto mais populares: Documentação do Produto Estrelas MkDocsGithub Repo: https://github.com/mkdocs/mkdocs Geração de documentação estática e dinâmica Simples, leve e construído em Python Caixa de pesquisa de texto completo inteligente Vários temas e plug-ins Suporte para Markdown e HTML Integração com páginas Git Extensível usando Python Arquitetura SPA 11.4k DocsifyGithub Repo: https://github.com/docsifyjs/docsify Nenhum arquivo html construído estaticamente Simples e leve (~ 21kB gzipado) Plug-in inteligente de pesquisa de texto completo Vários temas API de plugin simples Compatível com IE11 Suporte SSR Suporte a arquivos incorporados 16.5k DocusaurusGithub: https://github.com/facebook/docusaurus/ Desenvolvido por Markdown Construído usando React Pronto para traduções Controle de versão de documento Pesquisa de Documentos Configuração rápida 21.4k SlateGithub: https://github.com/slatedocs/slate Design limpo e intuitivo Documentação de página única Suporte a Markdown Destaque de sintaxe embutido Escreva amostras de código em vários idiomas Índice automático de rolagem suave A documentação é editável pelos usuários através do Github Suporte RTL 31.9k O IRIS Publisher no Open Exchange permite que você extraia blocos de documentação XData em HTML ou Markdown e gere o site de documentação de seu aplicativo usando MkDocs. Consulte as instruções no artigo: https://community.intersystems.com/post/creating-documentation-portal-your-intersystems-iris-application. Se você gostou, vote no meu app: https://openexchange.intersystems.com/contest/current Ref: https://dev.to/nafis/5-free-static-documentation-generators-you-must-check-out-5ged
Artigo
Yuri Marx · Mar. 23, 2022

Introdução ao Embbeded Python - Um processador de imagens como exemplo

A partir da versão 2021.2 do InterSystems IRIS é possível desenvolver serviços de backend, de integração e procedures de bancos de dados utilizando Python. A grande vantagem desta possibilidade é a redução na curva de aprendizado e a utilização de programadores especialistas na linguagem de programação que mais cresce no mundo. O propósito deste artigo é de demonstrar que os projetos criados em InterSystems IRIS podem ser desenvolvidos com Python, ou mesmo com Python e ObjectScript (linguagem de programação proprietária da InterSystems) juntos, para atender a quaisquer requisitos e necessidades do negócio. O desafio com este artigo é processar imagens de forma geral usando Python, uma vez que o ObjectScript não conta com funcionalidades nativas para isto. Para ilustrar na prática este casamento perfeito do Python e do InterSystems IRIS, foi criada uma aplicação de exemplo, o iris-image-editor. Esta aplicação possui as seguintes funcionalidades: Criação de thumbnail (miniatura) na imagem; Criação de marca d´agua na imagem; Criação de filtros na imagem, como filtro blur, dentre outros. Esta aplicação utiliza a biblioteca da comunidade Python Pillow (https://pillow.readthedocs.io/en/stable/). Ela permite realizar desde de operações básicas (leitura, gravação, corte, ampliação, redução, etc.), até as mais avançadas em imagens (aplicação de filtros em geral). Para obter e executar o iris-image-editor, siga os passos abaixo: Clone o repositório para um diretório local à sua escolha $ git clone https://github.com/yurimarx/iris-image-editor.git Abra o terminal do docker no diretório escolhido e execute: $ docker-compose build Execute o container do IRIS: $ docker-compose up -d Para criar thumbnails (miniaturas): Vá no seu Postman (ou cliente REST similar) e configure a requisição como na imagem a seguir, envie e veja a resposta: Method: POST URL: http://localhost:52773/iris-image-editor/thumbnail Body: form-data Key: file (o nome do campo file deve ser file) e o type File Value: arquivo do seu computador Para fazer a marca d´agua: Vá no seu Postman (ou outro cliente REST similar) e configure a requisição como na figura, envie e veja o resultado: Method: POST URL: http://localhost:52773/iris-image-editor/watermark Body: form-data Key: file (o nome do campo file deve ser file) e o tipo File Value: arquivo do seu computador Key: watermark (texto a ser escrito dentro da imagem) e o type é text Value: I'm a cat (ou outro valor que você queira) Para fazer filtros: Vá no seu Postman (ou outro cliente REST) e configurar a requisição como na imagem, envie e veja a resposta: Method: POST URL: http://localhost:52773/iris-image-editor/filter Body: form-data Key: file (o nome do campo deve ser file) e o type File Value: arquivo do seu computador Key: filter (deve ser este nome filter) e o tipo text Value: BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, SMOOTH, SMOOTH_MORE ou SHARPEN Como o Python foi utilizado dentro do IRIS neste exemplo: A primeira ação a ser tomada é ter o Python instalado junto ao IRIS, no nosso exemplo, utilizamos Docker para instalar e executar o IRIS. Sendo assim, incluimos a instalação do Python e da biblioteca Pillow no arquivo Dockerfile, veja: Trecho de código do Dockerfile responsável por instalar o Python, o PIP e o Pillow # install libraries required by Pillow to process images RUN apt-get -y update \ && apt-get -y install apt-utils \ && apt-get install -y build-essential unzip pkg-config wget \ && apt-get install -y python3-pip # use pip3 (the python zpm) to install Pillow dependencies RUN pip3 install --upgrade pip setuptools wheel RUN pip3 install --target /usr/irissys/mgr/python Pillow O apt-get install da biblioteca do Linux python3-pip, realiza a instalação do Python e do gerenciador de pacotes/bibliotecas do Python (como o ZPM do ObjectScript ou o Maven do Java), o PyPI (pip3). A partir do pip3 é possível instalar qualquer biblioteca conhecida do mundo Python, inclusive o Pillow. O comando pip3 install --target /usr/irissys/mgr/python Pillow instala o Pillow e suas dependências dentro do diretório no qual o IRIS procura bibliotecas Python para utilizar (quando no ambiente Linux). Uma vez que temos o Python e as bibliotecas necessárias instaladas, podemos agora criar nossos métodos de classe em linguagem Python, ao invés de utilizar ObjectScript. Neste exemplo criamos três métodos, todos na classe dc.imageeditor.ImageEditorService, detalhados abaixo: Método de Classe em Python para gerar thumbnails para imagens ClassMethod ProcessThumbnail(imageName) [ Language = python ] { #Import required Image library from PIL import Image # set folder to receive the image to be processed input_path = "/opt/irisbuild/input/" + imageName # set folder to stores the results (image processed) output_path = "/opt/irisbuild/output/" + imageName # open the original image image = Image.open(input_path) # reduce image size image.thumbnail((90,90)) # save the new image image.save(output_path) } O primeiro passo é declarar Language = python na declaração do método, assim o IRIS irá utilizar Python, ao invés de ObjectScript, que a linguagem padrão. A seguir, basta escrever todo o conteúdo do método em Python, como seria feito dentro de um arquivo .py. Este método importa o Pillow com o from PIL import Image. Em seguida são definidos os diretórios de origem da imagem e de destino da imagem processada. O Image.open, obtêm a imagem a ser processada. O image.thumbnail reduz o tamanho da imagem para as dimensões 90x90. O image.save grava o processamento no diretório de destino. Método de Classe em Python que escreve um texto como marca d'agua da imagem ClassMethod ProcessWartermarker(imageName, watermark) [ Language = python ] { #Import required Image library from PIL import Image, ImageDraw, ImageFont # set folder to receive the image to be processed input_path = "/opt/irisbuild/input/" + imageName # set folder to stores the results (image processed) output_path = "/opt/irisbuild/output/" + imageName # open the original image im = Image.open(input_path) # extract image dimensions width, height = im.size # get drawer draw = ImageDraw.Draw(im) # get text writer font = ImageFont.truetype("DejaVuSans.ttf", 32) textwidth, textheight = draw.textsize(watermark, font) # calculate the x,y coordinates of the text margin = 10 x = width - textwidth - margin y = height - textheight - margin # draw watermark in the bottom right corner draw.text((x, y), watermark, font=font) # save the new image im.save(output_path) } O Image.open() abre a imagem de origem. O im.size obtêm as dimensões da imagem. O ImageDraw.Draw obtem uma referência chamada draw que irá permitir a operação de escrita na imagem. O ImageFont.truetype() escolhe a fonte e tamanho do texto a ser escrito. É calculada a posição x,y do texto na image e o draw.text escreve o texto na fonte escolhida. A imagem final é gravada no diretório de destino. Método de Classe em Python para aplicar filtros avançados na imagem ClassMethod ProcessFilter(imageName, filter) [ Language = python ] { #Import required Image library from PIL import Image, ImageFilter #Import all the enhancement filter from pillow from PIL.ImageFilter import ( BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, SMOOTH, SMOOTH_MORE, SHARPEN ) # set folder to receive the image to be processed input_path = "/opt/irisbuild/input/" + imageName # set folder to stores the results (image processed) output_path = "/opt/irisbuild/output/" + imageName # open the original image im = Image.open(input_path) if filter == "BLUR": imFiltered = im.filter(BLUR) elif filter == "CONTOUR": imFiltered = im.filter(CONTOUR) elif filter == "DETAIL": imFiltered = im.filter(DETAIL) elif filter == "EDGE_ENHANCE": imFiltered = im.filter(CONTOUR) elif filter == "EDGE_ENHANCE_MORE": imFiltered = im.filter(EDGE_ENHANCE_MORE) elif filter == "EMBOSS": imFiltered = im.filter(EMBOSS) elif filter == "FIND_EDGES": imFiltered = im.filter(FIND_EDGES) elif filter == "SHARPEN": imFiltered = im.filter(SHARPEN) elif filter == "SMOOTH": imFiltered = im.filter(SMOOTH) elif filter == "SMOOTH_MORE": imFiltered = im.filter(SMOOTH_MORE) else: imFiltered = im # save the new image imFiltered.save(output_path) } O Image.open() abre a imagem de origem. O im.filter(NOME DO FILTRO) aplica o filtro e retorna uma refêrencia para a imagem processada. A imagem com o filtro aplicado é gravada no diretório de destino com imFiltered.save(). A interação entre o ObjectScript e o Python O exemplo também demonstra como é fácil para o ObjectScript realizar uma chamada para um método escrito em Python. É da mesma forma como seria chamado qualquer outro método. Veja este trecho de exemplo: ClassMethod DoThumbnail(Image As %String) As %Status { Do ..ProcessThumbnail(Image) Quit $$$OK } O método de classe escrito em Python está na mesma classe deste método de classe em ObjectScript, então basta utilizar .. seguido do nome do método e seus argumentos de chamada. O IRIS internamente realiza as conversões de tipos na ida e na volta para os argumentos. Se o método estiver em outra classe, basta utilizar Do ##class(pacote.NomeClasse).NomeMetodoPython(<argumentos>). Expondo as funcionalidades como API REST O IRIS possui extrema facilidade em expor métodos de classe como API REST, basta ter uma classe que herde de %CSP.REST. Nesta aplicação de exemplo isto foi feito a partir da classe dc.imageeditor.ImageEditorRESTApp. Veja: Classe responsável por expor as funcionalidades como API REST Class dc.imageeditor.ImageEditorRESTApp Extends %CSP.REST { Parameter CHARSET = "utf-8"; Parameter CONVERTINPUTSTREAM = 1; Parameter CONTENTTYPE = "application/json"; Parameter Version = "1.0.0"; Parameter HandleCorsRequest = 1; XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ] { <Routes> <!-- Server Info --> <Route Url="/" Method="GET" Call="GetInfo" Cors="true"/> <!-- Swagger specs --> <Route Url="/_spec" Method="GET" Call="SwaggerSpec" /> <!-- do a thumbnail --> <Route Url="/thumbnail" Method="POST" Call="DoThumbnail" /> <!-- do a watermark --> <Route Url="/watermark" Method="POST" Call="DoWatermark" /> <!-- do a image filter --> <Route Url="/filter" Method="POST" Call="DoFilter" /> </Routes> } /// Do thumbnail ClassMethod DoThumbnail() As %Status { Set tSC = $$$OK try { // get the file from the multipart request Set source = %request.GetMimeData("file") // save the file to the input folder, to be processed with imageai Set destination=##class(%Stream.FileBinary).%New() Set destination.Filename="/opt/irisbuild/input/"_source.FileName set tSC=destination.CopyFrom(source) //reader open the file set result=destination.%Save() //call embedded python classmethod to thumbnail the image Do ##class(dc.imageeditor.ImageEditorService).DoThumbnail(source.FileName) If ($FIND(source.FileName, "jpg") > 0) || ($FIND(source.FileName, "jpeg") > 0) { Set %response.ContentType = "image/jpeg" } ElseIf ($FIND(source.FileName, "png") > 0) { Set %response.ContentType = "image/png" } Else { Set %response.ContentType = "application/octet-stream" } Do %response.SetHeader("Content-Disposition","attachment;filename="""_source.FileName_"""") Set %response.NoCharSetConvert=1 Set %response.Headers("Access-Control-Allow-Origin")="*" Set stream=##class(%Stream.FileBinary).%New() Set sc=stream.LinkToFile("/opt/irisbuild/output/"_source.FileName) Do stream.OutputToDevice() Set tSC=$$$OK //returns error message to the user } catch e { Set tSC=e.AsStatus() Set pOutput = tSC } Quit tSC } /// Do Watermark ClassMethod DoWatermark() As %Status { Set tSC = $$$OK try { // get the file from the multipart request Set source = %request.GetMimeData("file") Set watermark = $Get(%request.Data(("watermark"),1)) // save the file to the input folder, to be processed with image editor Set destination=##class(%Stream.FileBinary).%New() Set destination.Filename="/opt/irisbuild/input/"_source.FileName set tSC=destination.CopyFrom(source) //reader open the file set result=destination.%Save() //call embedded python classmethod to thumbnail the image Do ##class(dc.imageeditor.ImageEditorService).DoWatermark(source.FileName, watermark) If ($FIND(source.FileName, "jpg") > 0) || ($FIND(source.FileName, "jpeg") > 0) { Set %response.ContentType = "image/jpeg" } ElseIf ($FIND(source.FileName, "png") > 0) { Set %response.ContentType = "image/png" } Else { Set %response.ContentType = "application/octet-stream" } Do %response.SetHeader("Content-Disposition","attachment;filename="""_source.FileName_"""") Set %response.NoCharSetConvert=1 Set %response.Headers("Access-Control-Allow-Origin")="*" Set stream=##class(%Stream.FileBinary).%New() Set sc=stream.LinkToFile("/opt/irisbuild/output/"_source.FileName) Do stream.OutputToDevice() Set tSC=$$$OK //returns error message to the user } catch e { Set tSC=e.AsStatus() Set pOutput = tSC } Quit tSC } /// Do filter ClassMethod DoFilter() As %Status { Set tSC = $$$OK try { // get the file from the multipart request Set source = %request.GetMimeData("file") Set filter = $Get(%request.Data(("filter"),1)) // save the file to the input folder, to be processed with image editor Set destination=##class(%Stream.FileBinary).%New() Set destination.Filename="/opt/irisbuild/input/"_source.FileName set tSC=destination.CopyFrom(source) //reader open the file set result=destination.%Save() //call embedded python classmethod to thumbnail the image Do ##class(dc.imageeditor.ImageEditorService).DoFilter(source.FileName, filter) If ($FIND(source.FileName, "jpg") > 0) || ($FIND(source.FileName, "jpeg") > 0) { Set %response.ContentType = "image/jpeg" } ElseIf ($FIND(source.FileName, "png") > 0) { Set %response.ContentType = "image/png" } Else { Set %response.ContentType = "application/octet-stream" } Do %response.SetHeader("Content-Disposition","attachment;filename="""_source.FileName_"""") Set %response.NoCharSetConvert=1 Set %response.Headers("Access-Control-Allow-Origin")="*" Set stream=##class(%Stream.FileBinary).%New() Set sc=stream.LinkToFile("/opt/irisbuild/output/"_source.FileName) Do stream.OutputToDevice() Set tSC=$$$OK //returns error message to the user } catch e { Set tSC=e.AsStatus() Set pOutput = tSC } Quit tSC } /// General information ClassMethod GetInfo() As %Status { SET version = ..#Version SET fmt=##class(%SYS.NLS.Format).%New("ptbw") SET info = { "Service": "Image Editor API", "version": (version), "Developer": "Yuri Gomes", "Status": "Ok", "Date": ($ZDATETIME($HOROLOG)) } Set %response.ContentType = ..#CONTENTTYPEJSON Set %response.Headers("Access-Control-Allow-Origin")="*" Write info.%ToJSON() Quit $$$OK } ClassMethod SwaggerSpec() As %Status { Set tSC = ##class(%REST.API).GetWebRESTApplication($NAMESPACE, %request.Application, .swagger) Do swagger.info.%Remove("x-ISC_Namespace") Set swagger.basePath = "/iris-tts" Set swagger.info.title = "TTS Service API" Set swagger.info.version = "1.0" Set swagger.host = "localhost:52773" Return ..%ProcessResult($$$OK, swagger) } ClassMethod %ProcessResult(pStatus As %Status = {$$$OK}, pResult As %DynamicObject = "") As %Status [ Internal ] { #dim %response As %CSP.Response SET tSC = $$$OK IF $$$ISERR(pStatus) { SET %response.Status = 500 SET tSC = ..StatusToJSON(pStatus, .tJSON) IF $isobject(tJSON) { SET pResult = tJSON } ELSE { SET pResult = { "errors": [ { "error": "Unknown error parsing status code" } ] } } } ELSEIF pStatus=1 { IF '$isobject(pResult){ SET pResult = { } } } ELSE { SET %response.Status = pStatus SET error = $PIECE(pStatus, " ", 2, *) SET pResult = { "error": (error) } } IF pResult.%Extends("%Library.DynamicAbstractObject") { WRITE pResult.%ToJSON() } ELSEIF pResult.%Extends("%JSON.Adaptor") { DO pResult.%JSONExport() } ELSEIF pResult.%Extends("%Stream.Object") { DO pResult.OutputToDevice() } QUIT tSC } } A classe extende de %CSP.REST e possui uma seção <Routes> responsável por criar as rotas (URL) HTTP para utilizar as funcionalidades. Na tag <Route> é definida a propriedade Url como o caminho HTTP utilizado para chamar o método de classe indicado na propriedade Call. O verbo HTTP é escolhido na propriedade Method. A chamada %request.GetMimeData() é responsável por receber os valores de input da requisição. O %response.ContentType define o tipo de retorno da requisição e a chamada %Stream.FileBinary.%New() permite obter uma referência para um arquivo, basta requisitar LinkToFile(), indicando o caminho para o arquivo. Por último é executado o OutputToDevice() para escrever o conteúdo do arquivo na resposta HTTP. Outras formas de utilizar o Python e IRIS juntos (fonte: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AEPYTHON) A partir do terminal do IRIS, é possível acionar o ambiente de execução do Python (shell): USER>do ##class(%SYS.Python).Shell() A partir de um programa Python é possível chamar Classes e Métodos ObjectScript # import the iris module and show the classes in this namespace import iris print('\nInterSystems IRIS classes in this namespace:') status = iris.cls('%SYSTEM.OBJ').ShowClasses() print(status) Ou >>> import iris >>> status = iris.cls('User.EmbeddedPython').Test() Fibonacci series: 0 1 1 2 3 5 8 InterSystems IRIS classes in this namespace: User.Company User.EmbeddedPython User.Person >>> print(status) 1 Em funções e Stored Procedures SQL: CREATE FUNCTION tzconvert(dt DATETIME, tzfrom VARCHAR, tzto VARCHAR) RETURNS DATETIME LANGUAGE PYTHON { from datetime import datetime from dateutil import parser, tz d = parser.parse(dt) if (tzfrom is not None): tzf = tz.gettz(tzfrom) d = d.replace(tzinfo = tzf) return d.astimezone(tz.gettz(tzto)).strftime("%Y-%m-%d %H:%M:%S") } A partir da classe utilitária %SYS.Python Class Demo.PDF { ClassMethod CreateSamplePDF(fileloc As %String) As %Status { set canvaslib = ##class(%SYS.Python).Import("reportlab.pdfgen.canvas") set canvas = canvaslib.Canvas(fileloc) do canvas.drawImage("C:\Sample\isc.png", 150, 600) do canvas.drawImage("C:\Sample\python.png", 150, 200) do canvas.setFont("Helvetica-Bold", 24) do canvas.drawString(25, 450, "InterSystems IRIS & Python. Perfect Together.") do canvas.save() } } Usando o Python Buitin Functions set builtins = ##class(%SYS.Python).Import("builtins") USER>do builtins.print("hello world!") hello world! Saiba mais: Documentação oficial: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AEPYTHON Concurso passado sobre Python com excelentes exemplo de uso: https://openexchange.intersystems.com/contest/21 Outros recursos: Learning Path Writing Python Application with InterSystems Embedded Python Documentation Native API for Python Documentation PEX Documentation
Artigo
Heloisa Paiva · Set. 22, 2022

Python e IRIS na prática - com exemplos!

Aqui você vai encontrar um programa simples que usa Python em um ambiente de desenvolvimento IRIS e outro programa simples que sua ObjectScript em um ambiente de desenvolvimento Python. Além disso, gostaria de compartilhar alguns dos problemas que tive enquanto aprendia a implementar esses códigos. Python em ambiente IRIS Digamos, por exemplo, que você está desenvolvendo no IRIS e tem um problema que acha mais fácil ou mais eficiente de se resolver com Python. Você pode simplesmente trocar o ambiente: crie seu método como qualquer outro, mas ao final do nome e de suas especificações, adicione [ Language = python ]: Você pode usar todo tipo de argumento no método e, para acessá-los, a lógica é exatamente a mesma que em COS: Temos um argumento %String, chamado Arg, e um argumento OtherArg que vem de uma classe customizada. Essa classe pode ter propriedades como Title e Author. Você pode acessá-las pelo nome: Esse método retorna um output desta forma: Para acessar métodos de classe, é basicamente o mesmo. Se há um método na classe Demo.Books.PD.Books (do OtherArg), chamado "CreateString", que concatena o título e o autor dados para algo do tipo "Title: <Title>; Author: <Author>", então, adicionar isso no final do nosso método python: acrescentará ao output: Para acessar o método, só é necessário OtherArg.CreateString(), mas eu escolhi passar os mesmos valores em OtherArg para o método com CreateString(OtherArg) para que os outputs ficassem parecidos e, consequentemente, o código ficasse mais simples. ObjectScript em ambiente Python Também pode haver situações em que você está desenvolvendo em ambiente Python, mas deseja as ferramentas do ObjectScript para ajudar. Primeiramente, é importante checar alguns itens desta lista para que possa acessar seus arquivos COS de um ambiente python de todas as maneiras (não vou necessariamente usar todas aqui nos exemplos): Você tem os pré-requisitos? Veja aqui Você pode usar um servidor externo de Python? Veja aqui Você tem todos os drivers necessários? Faça o download aqui ou Descubra mais aqui Você sempre pode retornar a esses links ou dar uma olhada na lista de erros que eu encontrei enquanto estava criando meus primeiros programas de Python com COS, se achar útil. Então, vamos começar a codar! Primeiro, vamos ter que adaptar algumas coisas do COS para o Python. Por sorte, a InterSystems já deixou isso pronto e só precisamos digitar "import iris" no começo do código para acessar tudo! No próximo passo, vamos criar uma conexão ao namespace desejado, usando um caminho com o host, port e namespace (host:port/namespace) e providenciando o usuário e senha: Observe como no final criamos um OBJETO IRIS, para utilizarmos essa conexão para ter acesso a tudo o que necessitamos no namespace. Finalmente, pode "codar" tudo o que quiser: Você pode acessar métodos com o irispy.classMethodValue() providenciando o nome da classe, do método e seus argumentos, manipular objetos com .set() (para propriedades) e muitas outras possibilidades, enquanto trata tudo com Python da forma preferida. Para mais informações sobre funções providenciadas pelo iris e como usá-las, visite o link Introduction to the Native SDK for Python Nesse exemplo, na linha 16 eu instanciei uma classe persistente para, nas linhas seguintes, dar os valores "Lord of The Rings" e "Tolkien" às propriedades Title e Author. Na linha 20, chamei um método de outra classe que salva o objeto a uma tabela e retorna um status se funcionou corretamente. Finalmente, imprimo o status na linha 23. Mix! Em um ambiente de ObjectScript, você pode precisar das Libraries conhecidas do Python, ou então de seus próprios arquivos customizados com funções ou rotinas. Você pode usar o comando "import" com Numpy, SciPy e qualquer outras que desejar (considerando que as tenha corretamente instaladas: veja aqui como fazer isso) Há muitas maneiras para acessar seus arquivos locais e é fácil achar tutoriais para isso na internet, considerando que Python é uma linguagem bem popular. Para mim, a mais fácil de trabalhar é a seguinte: Aqui, importei tudo do arquivo testesql.py, localizado em C:/python e imprimi os resultados da função select() Extras - problemas que encontrei SHELLS: Ao usar os Shells, lembre-se que o Windows PowerShell funciona como um sistema UNIX-based (já que é baseado em .NET) e o Command Prompt é o que vai funcionar corretamente com os exemplos de Windows na documentação oficial da InterSystems. Isso pode soar básico para alguns programadores mais experientes, mas se não estiver prestando atenção nesse detalhe pode perder um bom tempo tentando entender, então achei interessante pontuar isso aqui. USUÁRIOS E PRIVILÉGIOS: O usuário utilizado para programar com ObjectScript de um ambiente Python precisa ter privilégios aos recursos do Namespace. Lembre-se que se você não selecionar nenhum, o padrão é UnkownUser, e se não selecionar namespaces, o padrão é USER. Então, no acesso mais simples, siga: Portal de Administração > Administração do Sistema > Segurança > Usuários > UnknownUser > Roles, selecione %DB_USER e salve. SOCORRO, EU NEM SEI O QUE ESTÁ ACONTECENDO: Para checar mais informações sobre os erros que você está encotrando, siga: Portal de Administração > Explorer do Sistema > SQL e digite "SELECT * FROM %SYS.Audit ORDER BY UTCTimeStamp Desc" para retornar as audits mais recentes. (Lembre-se de checar o namespace para consultar essa query). Aí você irá encontrar as causas de erros como IRIS_ACCESSDENIED() e muito mais, que você pode encontrar até fora do ambiente IRIS. ERRO AO COMPILAR PYTHON: Evite dar nomes a métodos como try() ou outras funções prontas do Python. O compilador não entenderá a diferença do nome do Método para a função. Muito obrigada pela leitura e por favor, sinta-se à vontade para compartilhar sugestões, comentários ou dúvidas, ou simplesmente o que você estiver desenvolvendo!
Artigo
Danusa Calixto · Out. 27, 2022

Usando OAuth 2.0 / OIDC para login único em uma aplicação REST no IRIS

Digamos que eu esteja desenvolvendo uma aplicação web que usa o IRIS como back-end. Estou trabalhando nela com acesso não autenticado. Está chegando a hora em que eu gostaria de implantar para os usuários, mas preciso adicionar a autenticação primeiro. Em vez de usar a autenticação padrão de senha do IRIS, quero que os usuários façam login com o Login Único (single sign-on - SSO, na sigla em inglês) da minha organização ou outro provedor de identidade popular, como Google ou GitHub. Li que o OpenID Connect é um padrão de autenticação comum e compatível com o IRIS. Qual é a maneira mais simples de colocar isso em funcionamento? ### Exemplo 1: uma app CSP simples A documentação [aqui](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GOAUTH_client) apresenta uma opção bastante fácil para usar uma aplicação CSP como um cliente OpenID Connect. Estas são as etapas: 1. Configure o servidor OAuth 2.0 e a configuração do cliente no IRIS. Veja mais informações na seção "Caché configuration" do[excelente artigo do Daniel Kutac](https://community.intersystems.com/post/intersystems-iris-open-authorization-framework-oauth-20-implementation-part-1). 2. Copie a rotina OAUTH2.ZAUTHENTICATE do [repositório de amostras no GitHub](https://github.com/intersystems/Samples-Security/blob/master/rtn/OAUTH2.ZAUTHENTICATE.mac) para o namespace %SYS e renomeie como ZAUTHENTICATE. 3. Ative a autenticação delegada no sistema inteiro. 4. Crie uma página de login personalizada que seja uma extensão de %OAuth2.Login e substitua o método DefineParameters para especificar o nome do aplicativo OAuth 2.0 e os escopos: Class MyOAuth2.Login Extends %OAuth2.Login { ClassMethod DefineParameters(Output application As %String, Output scope As %String, Output responseMode As %String) { Set application="my application name" Set scope="openid profile email" Set responseMode=..#RESPONSEMODE Quit } } 5. Ative a aplicação web para a autenticação delegada e defina MyOAuth2.Login.cls como a página de login personalizada. 6. Um truque final: para a página de login personalizada funcionar, o usuário CSPSystem no IRIS precisa ter o acesso específico de LEITURA à base de dados em que está MyOAuth2.Login.cls. Neste momento, o login deve "simplesmente funcionar": a visita a uma página CSP nesta aplicação web redirecionará para a página de login no provedor de identidade. Depois de fazer o login, o usuário terá uma sessão CSP autenticada. O $username será igual ao identificador de sujeito do SSO/Google/GitHub/etc., então posso usar a autorização integrada do IRIS para determinar a que dar acesso. ### Exemplo 2: o problema com REST E se a aplicação web estiver usando um manipulador REST? O processo acima não funciona. Se uma aplicação web estiver habilitada para REST, não é possível definir uma página de login personalizada. Descobri que são necessárias mais algumas etapas para contornar isso. 7. Crie uma aplicação web separada sem REST habilitado. O caminho nessa app precisa começar com o caminho do app REST. Por exemplo, se o nome da app REST for "/csp/api", você poderá nomear essa nova app como "/csp/api/login". Ative a autenticação delegada e defina a página MyOAuth2.Login.cls como a página de login personalizada. 8. Defina o Caminho do Cookie da Sessão nessa nova app para o mesmo da app REST: por exemplo, "/csp/api". Assim, ambas as aplicações compartilharão uma sessão CSP. 9. Adicione uma página CSP a essa nova app para servir como uma "página inicial". Um usuário precisa primeiro acessar essa página para estabelecer sua sessão. Veja este exemplo que redireciona para um endpoint na API REST após o login: Class App.Home Extends %CSP.Page { ClassMethod OnPage() As %Status [ ServerOnly = 1 ] { &html<<script type="text/javascript"> window.location="/csp/api/test" </script>> return $$$OK } } 10. Certifique-se de que a classe do manipulador REST tenha o parâmetro UseSession substituído por true. Class API.REST Extends %CSP.REST { Parameter UseSession As BOOLEAN = 1; XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ] { <Routes> <Route Url="/test" Method="GET" Call="Test" Cors="true"/> </Routes> } ClassMethod Test() As %Status { write { "username": ($username) }.%ToJSON() return $$$OK } } Nesse ponto, o login na app REST também deverá "simplesmente funcionar". O usuário visitará a página inicial, será redirecionado para o login SSO e, finalmente, retornará a app REST, onde tem uma sessão CSP autenticada. Até onde sei, essa é a maneira mais fácil de adicionar o OpenID Connect a um app IRIS REST. Outra opção é usar a amostra "REST.ZAUTHENTICATE" do repositório de amostras de segurança. Com isso, espera-se que o front-end anexe um bearer token OAuth 2.0 a cada solicitação. No entanto, não há uma forma definida para o front-end obter esse token de acesso. Você terá que implementar esse fluxo OAuth por conta própria em JavaScript (ou usar uma biblioteca como [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc).) Você também precisará se certificar de que o app JavaScript e o back-end IRIS estejam de acordo em todos os itens de configuração, como o endpoint do emissor do servidor de autorização, o ID do cliente OAuth 2.0 etc. Descobri que essa não é uma tarefa simples. Tenho curiosidade para saber se mais alguém está usando o OpenID Connect para autenticar uma app IRIS. Há uma maneira ainda mais simples? Ou vale a pena usar a abordagem mais complicada com bearer tokens? Comente aqui embaixo.
Anúncio
Rochael Ribeiro · Jun. 6, 2022

Lançamentos da Comunidade de Desenvolvedores, Maio de 2022

Bem vindos aos Lançamentos de Maio de 2022 da Comunidade de Desenvolvedores! Disponibilizamos algumas melhorias para aprimorar sua experiência recentemente na Comunidade InterSystems: 🆕 Rastreamento aprimorado dos eventos atuais 🆕 Postagem agendada 🆕 Formatação de código aprimorada 🆕 Criação de tabelas mais rápida 🆕 Experiência de resposta enriquecida 🆕 Alterado a prévia de design de postagens Vamos dar uma olhada mais próxima em todos os detalhes. AO VIVO AGORA para Eventos Para tornar os eventos atuais mais fáceis e convenientes de se localizar adicionamos uma nova seção AO VIVO AGORA no canto superior esquerdo da página. E se você clicar nele, será redirecionado para a página do evento, onde você pode se juntar ao evento (se for online, claro) Para tirar vantagem do uso desta funcionalidade, seus anúncios de eventos devem atender as seguintes condições: Crie seu evento normalmente [adicione a tag Eventos -> campos especiais aparecerão automaticamente] Verifique se seu evento possui horários de início e fim específicos (eventos de dia todo não são tratados nesta seção) Para permitir que pessoas se juntem ao seu evento online diretamente, adicione a opção Link direto para participar É isso, pronto para publicar! Agende sua postagem Você pediu e nós fizemos! Agora você pode agendar sua postagem para que seja publicada em um horário específico. Para agendar sua postagem para mais tarde, você precisa apenas clicar na seta para baixo, próxima ao botão Publicar, e escolher Agendar postagem. Depois, você poderá escolher a data e horário de quando sua postagem será publicada. Escolhido o horário, clique no botão Agendar postagem. Sua postagem será publicada no horário escolhido - é isso! Formatação de Código Para compartilhar seu código com outros, adicionamos um editor embutido para quando ocorrer a inserção de códigos. In it, you can select the appropriate programming language and tab size. Assim, o destaque da sintaxe ocorre imediatamente ao se escrever o texto e a linguagem de programação é exibida no canto superior esquerdo. Como resultado, na sua postagem, você terá um bonito código formatado, na linguagem de programação selecionada. Criação de Tabelas Para facilitar a formatação no momento da criação de tabelas, adicionamos uma função para rapidamente criar uma tabela, através da seleção do número desejado de células. Se você clicar no botão Mais em baixo, será aberta a funcionalidade padrão de criação de tabelas. Respostas e assinaturas Para visualizar todas as informações sobre a discussão rapidamente, adicionamos o número de respostas no topo do editor e também um ícone para assinar uma discussão e assim, postar uma nova resposta. Design da Prévia da Postagem Para tornar a parte de baixo da postagem mais balanceada, rearranjamos e alteramos os ícones. Aproveitem as atualizações! Enviem-nos suas requisições por melhorias e notificações de problemas no GitHub da Comunidade de Desenvolvedores. Ou poste suas sugestões nos comentários desta postagem. Nos vemos em breve com mais mudanças interessantes!