Pesquisar

Limpar filtro
Artigo
Danusa Calixto · jan 11, 2023

Implementação do Open Authorization Framework do InterSystems IRIS (OAuth 2.0) - parte 3

Criado por Daniel Kutac, Engenheiro de vendas, InterSystems   Parte 3. Apêndice ## Explicação sobre as classes OAUTH do InterSystems IRIS Na [parte anterior ](https://pt.community.intersystems.com/post/implementação-do-open-authorization-framework-do-intersystems-iris-oauth-20-parte-2)da nossa série, aprendemos a configurar o InterSystems IRIS para atuar como um cliente OAUTH, além de um servidor de autorização e autenticação (pelo OpenID Connect). Nesta parte final da série, vamos descrever classes que implementam o framework OAuth 2.0 do InterSystems IRIS. Também vamos discutir casos de uso para métodos selecionados de classes de API. As classes de API que implementam o OAuth 2.0 podem ser separadas em três grupos diferentes de acordo com a finalidade. Todas as classes são implementadas no namespace %SYS. Algumas delas são públicas (por % pacote), outras não e não devem ser chamadas diretamente pelos desenvolvedores. ### Classes internas Estas classes pertencem ao pacote OAuth2. A tabela a seguir lista algumas classes de interesse (para uma lista completa de classes, consulte a Referência de Classes online da sua instância do Caché). Nenhuma dessas classes deve ser usada diretamente por desenvolvedores de aplicativos, exceto as listadas abaixo. Nome da classe Descrição OAuth2.AccessToken PersistentOAuth2.AccessToken armazena um token de acesso do OAuth 2.0 e as informações relacionadas. É uma cópia do cliente OAUTH do token de acesso. OAuth2.AccessToken é indexado pela combinação de SessionId e ApplicationName. Portanto, apenas um escopo pode ser solicitado para cada SessionId/ApplicationName. Se uma segunda solicitação for feita com um escopo diferente e o token de acesso ainda não tiver sido concedido, o escopo na nova solicitação se tornará o escopo esperado. OAuth2.Client Persistente A classe OAuth2.Application descreve um cliente OAuth2 e faz referência ao servidor de autorização que usa para autorizar o aplicativo com base no RFC 6749. Um sistema cliente pode ser usado com vários servidores de autorização para diferentes aplicativos. OAuth2.Response Página CSP É a página de destino para respostas de um servidor de autorização do OAuth 2.0 usado de código do cliente OAuth 2.0 do InterSystems IRIS. A resposta é processada aqui e redirecionada ao alvo final. OAuth2.ServerDefinition Persistente Armazena informações do servidor de autorização usadas por um cliente OAUTH (essa instância do InterSystems IRIS). Podem ser definidas várias configurações de cliente para cada definição de servidor de autorização. OAuth2.Server.AccessToken Persistente Os tokens de acesso são gerenciados pelo OAuth2.Server.AccessToken no servidor OAUTH. A classe armazena o token de acesso e as propriedades relacionadas. Essa classe também é o meio de comunicação entre várias partes do servidor de autorização. OAuth2.Server.Auth Página CSP O servidor de autorização apoia o fluxo de controle de autorização para o código de autorização e os tipos de concessão implícitos conforme a especificação no RFC 6749. A classe OAuth2.Server.Auth é uma subclasse de %CSP.Page que atua como o endpoint de autorização e controla o fluxo de acordo com o RFC 6749. OAuth2.Server.Client Persistente OAuth2.Server.Configuration é uma classe persistente que descreve os clientes registrados com esse servidor de autorização. OAuth2.Server.Configuration Persistente Armazena a configuração do servidor de autorização. Todas as classes de configuração têm uma página correspondente no Portal de Gerenciamento de Sistemas onde os usuários preenchem os detalhes da configuração. Objetos OAuth2.Client, OAuth2.ServerDefinition, OAuth2.Server.Client e OAuth2.Configuration podem ser abertos, modificados e salvos para criar ou modificar configurações sem usar a IU. Você pode usar essas classes para manipular configurações de maneira programática. ### Classes de personalização do servidor Estas classes pertencem ao pacote %OAuth2. O pacote contém um conjunto de classes internas — utilitários. Só descrevemos as classes que podem ser usadas por desenvolvedores. Estas classes são mencionadas na página de configuração do servidor do OAuth 2.0 %OAuth2.Server.Authenticate Página CSP %OAuth2.Server.Authenticate atua como uma subclasse para todas as classes Authenticate escritas por usuários, além da classe Authenticate padrão. A classe Authenticate é usada pelo endpoint de autorização no OAuth2.Server.Auth para autenticar o usuário. Essa classe permite a personalização do processo de autenticação.Os seguintes métodos talvez sejam implementados para substituir o padrão no OAuth2.Server:·        DirectLogin – use apenas quando não quiser mostrar a página de login·        DisplayLogin – implementa o formulário de login do servidor de autorização·        DisplayPermissions – implementa o formulário com uma lista de escopos solicitados Outras personalizações de aparência e visual podem ser feitas ao modificar o CSS. Os estilos CSS são definidos no método DrawStyle. loginForm é para o formulário DisplayLogin permissionForm é para o formulário DisplayPermissions %OAuth2.Server.Validate Página CSP Esta é a classe Validate User padrão incluída no servidor. A classe padrão usará o banco de dados do usuário da instância do Cache onde o servidor de autorização está localizado para validar o usuário. As propriedades aceitas serão o emissor (Issuer), as funções e o sub (Username). A Classe Validate User é especificada na configuração do servidor de autorização. Precisa conter um método ValidateUser, que validará uma combinação de nome de usuário/senha e retornará um conjunto de propriedades associadas ao usuário. %OAuth2.Server.Generate Objeto registrado O %OAuth2.Server.Generate é a classe Generate Token padrão incluída no servidor. A classe padrão gerará uma string aleatória como o token de acesso opaco. A classe Generate Token é especificada na configuração do servidor de autorização. Precisa conter um método GenerateAccessToken que será usado para gerar um token de acesso com base na array de propriedades retornada pelo método ValidateUser. %OAuth2.Server.JWT Objeto registrado O %OAuth2.Server.JWT é a classe Generate Token que cria um JSON Web Token incluído no servidor. A classe Generate Token é especificada na configuração do servidor de autorização. Precisa conter um método GenerateAccessToken que será usado para gerar um token de acesso com base na array de propriedades retornada pelo método ValidateUser. %OAuth2.Utils Objeto registrado Esta classe implementa, entre outros, o registro de várias entidades. Um código de amostra no capítulo Personalização mostra o possível uso. A imagem a seguir mostra a seção correspondente da configuração do servidor de autorização OAuth 2.0 ![](/sites/default/files/inline/images/1_7.png) Caso você use o OpenID Connect com token de identidade formatado JWT (id_token), substitua a classe Generate Token padrão _%OAuth2.Server.Generate_ com _%OAuth2.Server.JWT_ na configuração ou deixe a classe Generate padrão. Discutiremos as opções de personalização com mais detalhes mais tarde em um capítulo separado. ### Classes de API públicas As classes de API públicas são usadas por desenvolvedores de aplicativos para fornecer valores corretos para o fluxo de mensagens de aplicativos da Web, bem como para realizar a validação de tokens de acesso, introspecção e assim por diante. Essas classes são implementadas no pacote %SYS.OAuth2. A tabela lista algumas das classes implementadas. %SYS.OAuth2.AccessToken Objeto registrado A classe %SYS.OAuth2.AccessToken define as operações do cliente que permitem que um token de acesso seja usado para autorizar um servidor de recursos. O token subjacente é armazenado no OAuth2.AccessToken no banco de dados CACHESYS. OAuth2.AccessToken é indexado pela combinação de SessionId e ApplicationName. Portanto, apenas um escopo pode ser solicitado para cada SessionId/ApplicationName. Se uma segunda solicitação for feita com um escopo diferente e o token de acesso ainda não tiver sido concedido, o escopo na nova solicitação se tornará o escopo esperado. %SYS.OAuth2.Authorization Objeto registrado A classe %SYS.OAuth2.Authorization contém as operações usadas para autorizar um cliente ao obter um token de acesso. O token subjacente é armazenado no OAuth2.AccessToken no banco de dados CACHESYS. OAuth2.AccessToken é indexado pela combinação de SessionId e ApplicationName. Portanto, apenas um escopo pode ser solicitado para cada SessionId/ApplicationName. Se uma segunda solicitação for feita com um escopo diferente e o token de acesso ainda não tiver sido concedido, o escopo na nova solicitação se tornará o escopo esperado. Observe que essa classe está no CACHELIB e, portanto, disponível em qualquer lugar. No entanto, o armazenamento do token está no CACHESYS e, portanto, não está diretamente disponível para a maior parte do código. %SYS.OAuth2.Validation Objeto registrado A classe %SYS.OAuth2.Validation define os métodos usados para validar (ou invalidar) um token de acesso. O token subjacente é armazenado no OAuth2.AccessToken no banco de dados CACHESYS. OAuth2.AccessToken é indexado pela combinação de SessionId e ApplicationName. Portanto, apenas um escopo pode ser solicitado para cada SessionId/ApplicationName. Se uma segunda solicitação for feita com um escopo diferente e o token de acesso ainda não tiver sido concedido, o escopo na nova solicitação se tornará o escopo esperado. Vamos analisar alguns métodos e classes desse grupo mais a fundo. Cada classe de aplicação cliente, que usa o token de acesso, PRECISA conferir a validade dele. Isso é feito em algum lugar no método OnPage (ou o método correspondente na página ZENMojo ou ZEN). Este é o fragmento de código: // Check if we have an access token from oauth2 server set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,"scope1, scope2",.accessToken,.idtoken,.responseProperties,.error) // Continue with further checks if an access token exists. // Below are all possible tests and may not be needed in all cases. // The JSON object which is returned for each test is just displayed. if isAuthorized { // do whatever – call resource server API to retrieve data of interest } Sempre que chamamos a API do servidor de recursos, precisamos fornecer o token de acesso. Isso é feito pelo método **AddAccessToken** da classe _%SYS.OAuth2.AccessToken_, veja o fragmento de código aqui set httpRequest=##class(%Net.HttpRequest).%New() // AddAccessToken adds the current access token to the request. set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken( httpRequest,, ..#SSLCONFIG, ..#OAUTH2APPNAME) if $$$ISOK(sc) { set sc=httpRequest.Get(.. Service API url …) } No código de amostra fornecido nas partes anteriores da nossa série, é possível ver este código no método OnPreHTTP da primeira página do aplicativo (Cache1N). Esse é o melhor local para realizar a verificação do token de acesso para a página inicial do aplicativo. ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ] { set scope="openid profile scope1 scope2" #dim %response as %CSP.Response if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,, scope,.accessToken,.idtoken,.responseProperties,.error) { set %response.ServerSideRedirect="Web.OAUTH2.Cache2N.cls" } quit 1 } O método **IsAuthorized** da classe _SYS.OAuth2.AccessToken_ no código acima é verificar se o token de acesso válido existe e, se não existe, permite mostrar o conteúdo da página com um botão de login/link apontando para o formulário de autenticação do servidor de autorização. Caso contrário, redireciona para a segunda página, que faz o trabalho de recuperar os dados. Podemos, no entanto, alterar o código para que fique assim: ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ] { set scope="openid profile scope1 scope2" set sc=##class(%SYS.OAuth2.Authorization).GetAccessTokenAuthorizationCode( ..#OAUTH2APPNAME,scope,..#OAUTH2CLIENTREDIRECTURI,.properties) quit +sc } Essa variante tem um efeito diferente. Ao usar o método **GetAccessTokenAuthorizationCode** da classe _%SYS.OAuth2.Authorization_, navegamos diretamente até o formulário de autenticação do servidor de autenticação, sem mostrar o conteúdo da primeira página do nosso aplicativo. Isso pode ser útil nos casos em que o aplicativo da Web é invocado de um aplicativo nativo do dispositivo móvel, onde algumas informações do usuário já foram mostradas pelo aplicativo nativo (o launcher) e não há necessidade de exibir a página da Web com um botão apontando para o servidor de autorização. Se você usa o token JWT assinado, então precisa validar o conteúdo dele. Isso é feito pelo seguinte método: set valid=##class(%SYS.OAuth2.Validation).ValidateJWT(applicationName,accessToken,scope,,.jsonObject,.securityParameters,.sc) Veja a descrição detalhada dos parâmetros do método na documentação de Referência de Classes. ## Personalização Vamos passar algum tempo descrevendo quais opções o OAUTH oferece para a personalização da IU de autenticação/autorização. Suponha que a política da sua empresa exija um comportamento mais restritivo de concessão de escopo. Por exemplo, você pode executar um aplicativo de home banking que se conecta a vários sistemas bancários no seu banco. O banco só concede acesso ao escopo que contém informações sobre a conta bancária real que está sendo recuperada. Como o banco administra milhões de contas, é impossível definir o escopo estático para cada conta. Em vez disso, você pode gerar o escopo em tempo real — durante o processamento da autorização, como parte do código da página de autorização personalizada. Para o propósito da demonstração, precisamos adicionar mais um escopo à configuração do servidor — veja a imagem. ![](/sites/default/files/inline/images/2_2.png) Também adicionamos a referência à classe Authenticate personalizada, chamada %OAuth2.Server.Authenticate.Bank. Então, como é a classe de autenticação bancária? Veja uma possível variante da classe. Ela melhora os formulários de autenticação e autorização com dados fornecidos pelo usuário. As informações que fluem entre os métodos **BeforeAuthenticate**, **DisplayPermissions** e **AfterAuthenticate** são transmitidas pela variável de _propriedades_ da classe _%OAuth2.Server.Properties_ Class %OAuth2.Server.Authenticate.Bank Extends %OAuth2.Server.Authenticate { /// Add CUSTOM BESTBANK support for account scope. ClassMethod BeforeAuthenticate(scope As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status { // If launch scope not specified, then nothing to do If 'scope.IsDefined("account") Quit $$$OK // Get the launch context from the launch query parameter. Set tContext=properties.RequestProperties.GetAt("accno") // If no context, then nothing to do If tContext="" Quit $$$OK try { // Now the BestBank context should be queried. Set tBankAccountNumber=tContext // Add scope for accno. -> dynamically modify scope (no account:<accno> scope exists in the server configuration) // This particular scope is used to allow the same accno to be accessed via account // if it was previously selected by account or account:accno when using cookie support Do scope.SetAt("Access data for account "_tBankAccountNumber,"account:"_tBankAccountNumber) // We no longer need the account scope, since it has been processed. // This will prevent existence of account scope from forcing call of DisplayPermissions. Do scope.RemoveAt("account") // Add the accno property which AfterAuthenticate will turn into a response property Do properties.CustomProperties.SetAt(tBankAccountNumber,"account_number") } catch (e) { s ^dk("err",$i(^dk("err")))=e.DisplayString() } Quit $$$OK } /// Add CUSTOM BESTBANK support for account scope. /// If account_number custom property was added by either BeforeAuthenticate (account) /// or DisplayPermissions (account:accno), then add the needed response property. ClassMethod AfterAuthenticate(scope As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status { // There is nothing to do here unless account_number (account) or accno (account:accno) property exists try { // example of custom logging If $$$SysLogLevel>=3 { Do ##class(%OAuth2.Utils).LogServerScope("log ScopeArray-CUSTOM BESTBANK",%token) } If properties.CustomProperties.GetAt("account_number")'="" { // Add the accno query parameter to the response. Do properties.ResponseProperties.SetAt(properties.CustomProperties.GetAt("account_number"),"accno") } } catch (e) { s ^dk("err",$i(^dk("err")))=e.DisplayString() } Quit $$$OK } /// DisplayPermissions modified to include a text for BEST BANK account. ClassMethod DisplayPermissions(authorizationCode As %String, scopeArray As %ArrayOfDataTypes, currentScopeArray As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status { Set uilocales = properties.RequestProperties.GetAt("ui_locales") Set tLang = ##class(%OAuth2.Utils).SelectLanguage(uilocales,"%OAuth2Login") // $$$TextHTML(Text,Domain,Language) Set ACCEPTHEADTITLE = $$$TextHTML("OAuth2 Permissions Page","%OAuth2Login",tLang) Set USER = $$$TextHTML("User:","%OAuth2Login",tLang) Set POLICY = $$$TextHTML("Policy","%OAuth2Login",tLang) Set TERM = $$$TextHTML("Terms of service","%OAuth2Login",tLang) Set ACCEPTCAPTION = $$$TextHTML("Accept","%OAuth2Login",tLang) Set CANCELCAPTION = $$$TextHTML("Cancel","%OAuth2Login",tLang) &html<<html>> Do ..DrawAcceptHead(ACCEPTHEADTITLE) Set divClass = "permissionForm" Set logo = properties.ServerProperties.GetAt("logo_uri") Set clientName = properties.ServerProperties.GetAt("client_name") Set clienturi = properties.ServerProperties.GetAt("client_uri") Set policyuri = properties.ServerProperties.GetAt("policy_uri") Set tosuri = properties.ServerProperties.GetAt("tos_uri") Set user = properties.GetClaimValue("preferred_username") If user="" { Set user = properties.GetClaimValue("sub") } &html<<body>> &html<<div id="topLabel"></div>> &html<<div class="#(divClass)#">> If user '= "" { &html< <div> <span id="left" class="userBox">#(USER)#<br>#(##class(%CSP.Page).EscapeHTML(user))#</span> > } If logo '= "" { Set espClientName = ##class(%CSP.Page).EscapeHTML(clientName) &html<<span class="logoClass"><img src="#(logo)#" alt="#(espClientName)#" title="#(espClientName)#" align="middle"></span>> } If policyuri '= "" ! (tosuri '= "") { &html<<span id="right" class="linkBox">> If policyuri '= "" { &html<<a href="#(policyuri)#" target="_blank">#(POLICY)#</a><br>> } If tosuri '= "" { &html<<a href="#(tosuri)#" target="_blank">#(TERM)#</a>> } &html<</span>> } &html<</div>> &html<<form>> Write ##class(%CSP.Page).InsertHiddenField("","AuthorizationCode",authorizationCode),! &html<<div>> If $isobject(scopeArray), scopeArray.Count() > 0 { Set tTitle = $$$TextHTML(" is requesting these permissions:","%OAuth2Login",tLang) &html<<div class="permissionTitleRequest">> If clienturi '= "" { &html<<a href="#(clienturi)#" target="_blank">#(##class(%CSP.Page).EscapeHTML(clientName))#</a>> } Else { &html<#(##class(%CSP.Page).EscapeHTML(clientName))#> } &html<#(##class(%CSP.Page).EscapeHTML(tTitle))#</div>> Set tCount = 0 Set scope = "" For { Set display = scopeArray.GetNext(.scope) If scope = "" Quit Set tCount = tCount + 1 If display = "" Set display = scope Write "<div class='permissionItemRequest'>"_tCount_". "_##class(%CSP.Page).EscapeHTML(display)_"</div>" } } If $isobject(currentScopeArray), currentScopeArray.Count() > 0 { Set tTitle = $$$TextHTML(" already has these permissions:","%OAuth2Login",tLang) &html<<div>> &html<<div class="permissionTitleExisting">> If clienturi '= "" { &html<<a href="#(clienturi)#" target="_blank">#(##class(%CSP.Page).EscapeHTML(clientName))#</a>> } Else { &html<#(##class(%CSP.Page).EscapeHTML(clientName))#> } &html<#(##class(%CSP.Page).EscapeHTML(tTitle))#</div>> Set tCount = 0 Set scope = "" For { Set display = currentScopeArray.GetNext(.scope) If scope = "" Quit Set tCount = tCount + 1 If display = "" Set display = scope Write "<div class='permissionItemExisting'>"_tCount_". "_##class(%CSP.Page).EscapeHTML(display)_"</div>" } &html<</div>> } /*********************************/ /* BEST BANK CUSTOMIZATION */ /*********************************/ try { If properties.CustomProperties.GetAt("account_number")'="" { // Display the account number obtained from account context. Write "<div class='permissionItemRequest'><b>Selected account is "_properties.CustomProperties.GetAt("account_number")_"</b></div>",! // or, alternatively, let user add some more information at this stage (e.g. linked account number) //Write "<div>Account Number: <input type='text' id='accno' name='p_accno' placeholder='accno' autocomplete='off' ></div>",! } } catch (e) { s ^dk("err",$i(^dk("err")))=e.DisplayString() } /* original implementation code continues here... */ &html< <div><input type="submit" id="btnAccept" name="Accept" value="#(ACCEPTCAPTION)#"/></div> <div><input type="submit" id="btnCancel" name="Cancel" value="#(CANCELCAPTION)#"/></div> > &html<</form> </div>> Do ..DrawFooter() &html<</body>> &html<<html>> Quit 1 } /// For CUSTOM BESTBANK we need to validate that patient entered, /// ! javascript in this method is only needed when we let user enter some addtional data /// within DisplayPermissions method ! ClassMethod DrawAcceptHead(ACCEPTHEADTITLE) { &html<<head><title>#(ACCEPTHEADTITLE)#</title>> Do ..DrawStyle() &html< <script type="text/javascript"> function doAccept() { var accno = document.getElementById("accno").value; var errors = ""; if (accno !== null) { if (accno.length < 1) { errors = "Please enter account number name"; } } if (errors) { alert(errors); return false; } // submit the form return true; } </script> > &html<</head>> } } Como você pode ver, a classe %OAuth2.Server.Properties contém várias arrays, que são passadas. São elas: ·        RequestProperties — contém parâmetros da solicitação de autorização ·        CustomProperties — contêiner para a troca de dados entre o mencionado acima ·        ResponseProperties — contêiner para as propriedades serem adicionadas ao objeto de resposta JSON a uma solicitação de token ·        ServerProperties — contém propriedades compartilhadas que o servidor de autorização expõe para o código de personalização (por exemplo, logo_uri, client_uri, etc…) Além disso, ela contém várias propriedades de "declarações", que são usadas para especificar quais declarações devem ser retornadas pelo servidor de autorização. Para chamar essa página de autenticação corretamente, modificamos nosso código inicial da página do cliente para que fique assim: set scope="openid profile scope1 scope2 account" // this data comes from application (a form data or so...) and sets a context for our request // we can, through subclassing the Authenticate class, display this data to user so he/she can decide // whether to grant access or not set properties("accno")="75-452152122-5320" set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint( ..#OAUTH2APPNAME, scope, ..#OAUTH2CLIENTREDIRECTURI, .properties, .isAuthorized, .sc) if $$$ISERR(sc) { write "GetAuthorizationCodeEndpoint Error=" write ..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",! } Como você pode ver, adicionamos o escopo da conta e o nó "accno" da array de propriedades com um valor de contexto, que pode se originar em diferentes partes do nosso aplicativo. Esse valor é transmitido dentro do token de acesso ao servidor de recursos para processamento adicional. Existe um cenário da vida real que usa a lógica descrita acima — o padrão FHIR para a troca de históricos eletrônicos de pacientes. Depuração O framework do OAUTH tem depuração integrada. Isso é muito útil, pois toda a comunicação entre o cliente e os servidores é criptografada. O recurso de depuração permite capturar dados de tráfego gerados pelas classes de API antes que sejam enviados pela rede. Para depurar seu código, você pode implementar uma rotina ou classe simples de acordo com o código abaixo. Você precisa implementar este código em todas as instâncias de comunicação do InterSystems IRIS! Nesse caso, é melhor fornecer um nome de arquivo que indique a função dele dentro do processo de fluxo do OAUTH. (O código de amostra abaixo é salvo como uma rotina rr.mac, mas você decide o nome.) // d start^rr() start() public { new $namespace set $namespace="%sys" kill ^%ISCLOG set ^%ISCLOG=5 set ^%ISCLOG("Category","OAuth2")=5 set ^%ISCLOG("Category","OAuth2Server")=5 quit } // d stop^rr() stop() public { new $namespace set $namespace="%sys" set ^%ISCLOG=0 set ^%ISCLOG("Category","OAuth2")=0 set ^%ISCLOG("Category","OAuth2Server")=0 quit } // display^rr() display() public { new $namespace set $namespace="%sys" do ##class(%OAuth2.Utils).DisplayLog("c:\temp\oauth2_auth_server.log") quit } Em seguida, antes de começar a testar, abra um terminal e invoque d start^rr() em todos os nós do InterSystems IRIS (cliente, servidor de autorização ou servidor de recursos). Depois de concluído, execute d stop^rr() e d display^rr() para preencher os arquivos de log. Resumo Nesta série de artigos, aprendemos a usar a implementação do OAuth 2.0 do InterSystems IRIS. Começando com a demonstração simples do aplicativo cliente na parte 1, seguido pela amostra complexa descrita na parte 2. Por fim, descrevemos as classes mais importantes da implementação do OAuth 2.0 e explicamos quando elas devem ser chamadas nos aplicativos dos usuários. Quero agradecer em especial a Marvin Tener, pela paciência infinita ao responder às minhas perguntas, às vezes idiotas, e por revisar a série.
Artigo
Danusa Calixto · Nov. 19, 2022

Implementação do Open Authorization Framework do InterSystems IRIS (OAuth 2.0) - parte 2

Criado por Daniel Kutac, Engenheiro de vendas, InterSystems _Aviso: se você ficar confuso com os URLs usados: a série original usou telas de uma máquina chamada dk-gs2016. As novas capturas de tela foram tiradas em uma máquina diferente. Você pode tratar o URL WIN-U9J96QBJSAG como se fosse o dk-gs2016 com segurança._ _Parte 2. Servidor de autorização, servidor OpenID Connect_ Na [parte anterior](https://pt.community.intersystems.com/post/implementa%C3%A7%C3%A3o-do-open-authorization-framework-oauth-20-na-intersystems-iris-%E2%80%93-parte-1) desta série curta, aprendemos sobre o caso de uso simples – atuando como um cliente OAUTH[[1](#note1)]. Agora, é hora de levar nossa experiência a um nível completamente novo. Vamos construir um ambiente muito mais complexo, onde o InterSystems IRIS vai desempenhar todas as funções OAUTH. Já sabemos como fazer um cliente, então vamos nos concentrar no servidor de autorização e, ainda mais, no provedor OpenID Connect[[2](#note2)]. Como na parte anterior, precisamos preparar o ambiente. Desta vez, será mais complicado, pois há mais partes móveis. Antes de entrarmos nos detalhes do nosso exemplo, precisamos falar algumas palavras sobre o OpenID Connect. Como você deve lembrar, na parte anterior, recebemos a solicitação – para ter a autorização do Google – para nos autenticarmos primeiro com o Google. A autenticação não faz parte do framework OAUTH. Na verdade, há vários frameworks de autenticação, independentes do OAUTH. Um deles é chamado OpenID. Originalmente uma iniciativa independente, ele agora aproveita a infraestrutura fornecida pelo framework OAUTH, ou seja, as estruturas de comunicação e dados. Assim, nasceu o OpenID Connect. Na verdade, muitas pessoas o chamam de OAUTH em esteroides. De fato, com o OpenID Connect, você pode não só autorizar, mas também autenticar usando interfaces bem conhecidas do framework OAUTH. # **Demonstração complexa do OpenID Connect** Aproveitaremos grande parte do código do cliente da parte 1. Isso nos poupa muito trabalho, para que possamos nos concentrar na configuração do ambiente. ## **Pré-requisitos** Desta vez, precisamos adicionar uma infraestrutura PKI ao servidor web já existente com SSL habilitado. Precisamos de criptografia exigida pelo OpenID Connect. Se você quer autenticar alguém, precisa ter certeza absoluta de que ninguém mais pode se passar pelo agente (cliente, servidor de autenticação...) que envia os dados confidenciais pela rede. É aqui que entra a criptografia baseada em X.509. Observação: a partir do Cache 2017.1, não é mais necessário usar certificados X.509 para gerar JWT/JWKS (JSON Web Key Set). Devido à compatibilidade com versões anteriores e simplicidade, usamos essa opção. ### **PKI** A rigor, não precisamos usar a infraestrutura Caché PKI, mas é mais conveniente do que usar ferramentas como openssl diretamente para gerar todos os certificados. Não entraremos em detalhes sobre a geração de certificados aqui, pois você pode encontrá-los na [documentação](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCAS_pki#GCAS_C157792) do InterSystems IRIS. Como resultado da geração de certificados, criaremos 3 pares de chaves públicas/privadas e certificados associados. Vamos chamá-los de ·        root_ca (root_ca.cer) para nossa autoridade de certificação emissora ·        auth (auth.cer e auth.key) para o servidor de autorização e OpenID ·        client (client.cer e client.key) para o servidor de aplicação do cliente   ### **Credenciais X.509** Precisamos definir credenciais X.509 em servidores individuais para que eles possam assinar e validar JSON Web Tokens (JWT) trocados durante nossa demonstração ### **Configuração do servidor de autenticação e autorização** Sem entrar em detalhes sobre como definir credenciais X.509, apenas mostramos uma captura de tela das credenciais da instância AUTHSERVER. ![](/sites/default/files/inline/images/1_4.png) Como a imagem indica, o AUTHSERVER possui a própria chave privada e o certificado, enquanto só possui o certificado com a chave pública de CLIENT ### **Configuração do servidor cliente** Da mesma forma, as credenciais definidas na instância CLIENT ![](/sites/default/files/inline/images/2_0.png) Aqui o CLIENTE possui a chave privada e o certificado, mas somente o certificado com chave pública de AUTHSERVER. ### **Configuração do servidor de recursos** Não precisamos definir credenciais X509 na instância RESSERVER em nossa configuração de exemplo. ## **Configuração do OAUTH** Como a configuração descrita na parte 1 desta série, precisamos configurar nossos servidores para OAUTH. Vamos começar com a instância AUTHSERVER, pois é o componente central na configuração geral do OAUTH. ### **AUTHSERVER** No Portal de Gerenciamento de Sistemas, acesse **System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Server Configuration (Configuração do Servidor).** Clique no link do menu e preencha os itens do formulário: ·        nome do host ·        porta (opcional) ·        prefixo (opcional) – esses três campos compõem o Issuer endpoint (endpoint do emissor) ·        especifique as condições para retornar o token de atualização ·        verifique os tipos de concessão compatíveis, para nossa demonstração basta verificar todos os quatro tipos. No entanto, apenas o código de autorização é usado. ·        opcionalmente, confira o público-alvo necessário – isso adiciona a propriedade aud no código de autorização e solicitações implícitas ·        opcionalmente, confira a sessão de usuário de suporte - isso significa que o cookie httpOnly é usado pelo servidor de autorização para manter o usuário atual deste navegador conectado.  A segunda solicitação e as solicitações subsequentes do token de acesso não pedirão o nome de usuário e a senha. ·        especifique os intervalos de endpoint ·        defina os escopos compatíveis com esse servidor ·        aceite o padrão ou insira valores de opções de personalização – observação: altere o valor da classe de token Generate de %OAuth2.Server.Generate para %OAuth2.Server.JWT para que um JWT seja usado como token de acesso em vez de um token opaco. ·        forneça o nome da configuração SSL registrada para estabelecer o SSL sobre o HTTP conforme exigido pelo OAuth 2.0 ·        Preencha as configurações do JSON Web Token (JWT)  Veja esta captura de tela da configuração de exemplo ![](/sites/default/files/inline/images/4_4_1.png) ![](/sites/default/files/inline/images/5_3_0.png) ![](/sites/default/files/inline/images/6_2_1.png) ![](/sites/default/files/inline/images/7_0_1.png) ![](/sites/default/files/inline/images/8_0.png) Após definir a configuração do servidor, precisamos fornecer a configuração do cliente do servidor. Na página com o formulário de configuração do servidor, clique no botão Client Configurations e pressione Create New Configuration for your CLIENT and RESSERVER instances (Criar nova configuração para as instâncias CLIENT e RESSERVER). Esta imagem mostra a configuração do CLIENT. ![](/sites/default/files/inline/images/9_0.png) ![](/sites/default/files/inline/images/10_0.png) ![](/sites/default/files/inline/images/11_0.png) Deixe a guia JWT Token vazia — com valores padrão. Como você pode ver, nós preenchemos os campos com dados sem sentido, diferente de um caso de aplicação real. Da mesma forma, a configuração do RESSERVER ![](/sites/default/files/inline/images/12_0.png) ![](/sites/default/files/inline/images/13_0.png) Como você pode ver, há apenas informações muito básicas necessárias para o servidor de recursos, ou seja, você precisa definir o tipo de cliente para o servidor de recursos. Com CLIENT, você precisa fornecer mais informações, o tipo de cliente (confidencial, pois nosso cliente é executado como um web app capaz de manter o cliente em segredo no servidor, e não enviar para o agente cliente). ### **CLIENT** No SMP, acesse **System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Client Configurations (Configurações do cliente)**. Clique no botão Create Server Configuration (Criar configuração de servidor), preencha o formulário e salve. ![](/sites/default/files/inline/images/14_0.png) Confira se o endpoint do emissor corresponde ao valor que definimos anteriormente na instância AUTHSERVER! Você também precisa modificar os endpoints do servidor de autorização de acordo com a configuração do seu servidor web. No nosso caso, apenas incorporamos 'authserver' em cada campo de entrada. Agora, clique no link **Client Configurations** (Configurações do cliente) ao lado do Issuer Endpoint (Endpoint emissor) recém-criado e clique no botão **Create Client Configuration (Criar configuração de cliente)**. ![](/sites/default/files/inline/images/15_0.png) ![](/sites/default/files/inline/images/16.png) ![](/sites/default/files/inline/images/17.png) ![](/sites/default/files/inline/images/18.png) Ótimo! Agora, temos CLIENT e AUTHSERVER configurados. Isso pode ser suficiente para muitos casos de uso, pois o servidor de recursos pode ser apenas um namespace de AUTHSERVER, já protegido. Porém, vamos considerar que queremos cobrir um caso de uso em que um médico externo está tentando recuperar dados do nosso sistema clínico interno. Portanto, para permitir que esse médico recupere os dados, queremos armazenar as informações da conta dele DENTRO do nosso servidor de recursos para auditorias e fins forenses. Nesse caso, precisamos continuar e definir as configurações em RESSERVER. ### **RESSERVER** No SMP, acesse **System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Client Configurations (Configurações do cliente)**. Clique no botão **Create Server Configuration (Criar configuração de servidor)**, preencha o formulário e salve. ![](/sites/default/files/inline/images/19.png) Usamos a função de descoberta, um novo recurso implementado no Cache 2017.1 Como você pode ver, essa configuração está usando os mesmos dados que a configuração correspondente na instância CLIENT. Agora, clique no link **Client Configurations** (Configurações do cliente) ao lado do Issuer Endpoint (Endpoint emissor) recém-criado e clique no botão **Create Client Configuration (Criar configuração de cliente)**. ![](/sites/default/files/inline/images/20.png) ![](/sites/default/files/inline/images/21.png) A criação do WT a partir das credenciais X.509 não é recomendada, mas nós as usamos para a compatibilidade. ![](/sites/default/files/inline/images/22.png) Isso! Foi um processo tedioso, mas necessário. Agora, podemos avançar e começar a programar! ## **Aplicativo cliente** Para manter as coisas o mais simples possível, reciclaremos grande parte do código do nosso exemplo do Google que descrevemos na parte 1. O aplicativo cliente tem apenas duas páginas de CSP, sendo executado no aplicativo /csp/myclient, sem segurança aplicada – ele é apenas executado como usuário não autenticado. ### **Página 1** Class Web.OAUTH2.Cache1N Extends %CSP.Page { Parameter OAUTH2CLIENTREDIRECTURI = "https://dk-gs2016/client/csp/myclient/Web.OAUTH2.Cache2N.cls"; Parameter OAUTH2APPNAME = "demo client"; ClassMethod OnPage() As %Status { &html // Get the url for authorization endpoint with appropriate redirect and scopes. // The returned url is used in the button below. // DK: use 'dankut' account to authenticate! set scope="openid profile scope1 scope2" set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint( ..#OAUTH2APPNAME, scope, ..#OAUTH2CLIENTREDIRECTURI, .properties, .isAuthorized, .sc) if $$$ISERR(sc) { write "GetAuthorizationCodeEndpoint Error=" write ..EscapeHTML($system.Status.GetErrorText(sc))_"",! } &html< Authorize for ISC > Quit $$$OK } ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ] { #dim %response as %CSP.Response set scope="openid profile scope1 scope2" if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error) { set %response.ServerSideRedirect="Web.OAUTH2.Cache2N.cls" } quit 1 } } ### **Página 2** Class Web.OAUTH2.Cache2N Extends %CSP.Page { Parameter OAUTH2APPNAME = "demo client"; Parameter OAUTH2ROOT = "https://dk-gs2016/resserver"; Parameter SSLCONFIG = "SSL4CLIENT"; ClassMethod OnPage() As %Status {     &html          // Check if we have an access token from oauth2 server     set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,"scope1 scope2",.accessToken,.idtoken,.responseProperties,.error)          // Continue with further checks if an access token exists.     // Below are all possible tests and may not be needed in all cases.     // The JSON object which is returned for each test is just displayed.     if isAuthorized {         write "Authorized!",!                           // Validate and get the details from the access token, if it is a JWT.         set valid=##class(%SYS.OAuth2.Validation).ValidateJWT(..#OAUTH2APPNAME,accessToken,"scope1 scope2",,.jsonObject,.securityParameters,.sc)         if $$$ISOK(sc) {             if valid {                 write "Valid JWT"_"",!                 } else {                 write "Invalid JWT"_"",!                 }             write "Access token="             do jsonObject.%ToJSON()             write "",!         } else {             write "JWT Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"",!             }         write "",!         // Call the introspection endpoint and display result -- see RFC 7662.         set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection(..#OAUTH2APPNAME,accessToken,.jsonObject)         if $$$ISOK(sc) {             write "Introspection="             do jsonObject.%ToJSON()             write "",!         } else {             write "Introspection Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"",!             }         write "",!                  if idtoken'="" {             // Validate and display the IDToken -- see OpenID Connect Core specification.             set valid=##class(%SYS.OAuth2.Validation).ValidateIDToken(                 ..#OAUTH2APPNAME,                 idtoken,                 accessToken,,,                 .jsonObject,                 .securityParameters,                 .sc)             if $$$ISOK(sc) {                 if valid {                     write "Valid IDToken"_"",!                     } else {                     write "Invalid IDToken"_"",!                     }                 write "IDToken="                 do jsonObject.%ToJSON()                 write "",!             } else {                 write "IDToken Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"",!                 }         } else {             write "No IDToken returned"_"",!         }         write "",!              // not needed for the application logic, but provides information about user that we can pass to Delegated authentication              // Call the userinfo endpoint and display the result -- see OpenID Connect Core specification.         set sc=##class(%SYS.OAuth2.AccessToken).GetUserinfo(             ..#OAUTH2APPNAME,             accessToken,,             .jsonObject)         if $$$ISOK(sc) {             write "Userinfo="             do jsonObject.%ToJSON()             write "",!         } else {             write "Userinfo Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"",!             }         write "",!         /***************************************************         *                                                  *         *   Call the resource server and display result.   *         *                                                  *         ***************************************************/                          // option 1 - resource server - by definition - trusts data coming from authorization server,         //     so it serves data to whoever is asking         //  as long as access token passed to resource server is valid                  // option 2 - alternatively, you can use delegated authentication (OpenID Connect)          //  and call into another CSP application (with delegated authentication protection)         //  - that's what we do here in this demo                           write "Call resource server (delegated auth)","",!         set httpRequest=##class(%Net.HttpRequest).%New()         // AddAccessToken adds the current access token to the request.         set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(             httpRequest,,             ..#SSLCONFIG,             ..#OAUTH2APPNAME)         if $$$ISOK(sc) {             set sc=httpRequest.Get(..#OAUTH2ROOT_"/csp/portfolio/oauth2test.demoResource.cls")         }         if $$$ISOK(sc) {             set body=httpRequest.HttpResponse.Data             if $isobject(body) {                 do body.Rewind()                 set body=body.Read()             }             write body,"",!         }         if $$$ISERR(sc) {             write "Resource Server Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"",!             }         write "",!              write "Call resource server - no auth, just token validity check","",!         set httpRequest=##class(%Net.HttpRequest).%New()         // AddAccessToken adds the current access token to the request.         set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(             httpRequest,,             ..#SSLCONFIG,             ..#OAUTH2APPNAME)         if $$$ISOK(sc) {             set sc=httpRequest.Get(..#OAUTH2ROOT_"/csp/portfolio2/oauth2test.demoResource.cls")         }         if $$$ISOK(sc) {             set body=httpRequest.HttpResponse.Data             if $isobject(body) {                 do body.Rewind()                 set body=body.Read()             }             write body,"",!         }         if $$$ISERR(sc) {             write "Resource Server Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"",!             }         write "",!     } else {         write "Not Authorized!",!         write "Authorize me"     }         &html     Quit $$$OK } } As seguintes capturas de tela retratam o processamento: Página de login do servidor de autenticação do OpenID Connect/autorização na instância AUTHSERVER ![](/sites/default/files/inline/images/11.png) Página de consentimento do usuário em AUTHSERVER ![](/sites/default/files/inline/images/12.png) E, por fim, a página resultante ![](/sites/default/files/inline/images/13.png) Como você pode ver, lendo o código, realmente quase não há diferença em relação ao código do cliente que mostramos na parte 1. Há algo novo na página 2. São algumas informações de depuração e a verificação da validade do JWT. Depois de validar o JWT retornado, podemos realizar a introspeção dos dados do AUTHSERVER sobre a identidade do usuário. Simplesmente apresentamos essas informações nos resultados da página, mas podemos fazer mais com elas. Como no caso de uso de um médico externo mencionado acima, podemos usar as informações de identidade e transmiti-las ao servidor de recursos para fins de autenticação, se necessário. Ou apenas passar essa informação como um parâmetro para a chamada da API ao servidor de recursos. Os próximos parágrafos descrevem como usamos as informações de identidade do usuário em mais detalhes. ## **Aplicativo de recurso** O servidor de recursos pode ser o mesmo servidor que o servidor de autorização/autenticação e, muitas vezes, esse é o caso. No entanto, na nossa demonstração, criamos para os dois servidores instâncias do InterSystems IRIS separadas. Então, temos dois casos possíveis, como trabalhar com o contexto de segurança no servidor de recursos. ### **Alternativa 1 — sem autenticação** Esse é o caso simples. O servidor de autorização/autenticação são apenas a mesma instância do Caché. Nesse caso, podemos simplesmente transmitir o token de acesso a um aplicativo CSP, que é criado especialmente para um único propósito — enviar dados a aplicativos clientes que usam o OAUTH para autorizar a solicitação de dados. A configuração do aplicativo CSP de recurso (chamamos de /csp/portfolio2) pode parecer com a captura de tela abaixo. ![](/sites/default/files/inline/images/14.png) Colocamos o mínimo de segurança na definição do aplicativo, permitindo que apenas a página CSP específica seja executada. Como opção, o servidor de recursos pode fornecer uma API REST em vez de páginas da Web clássicas. Em situações reais, o refinamento do contexto de segurança depende do usuário. Um exemplo de código-fonte: Class oauth2test.demoResource Extends %CSP.Page { ClassMethod OnPage() As %Status { set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.sc) if $$$ISOK(sc) { set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection("RESSERVER resource",accessToken,.jsonObject) if $$$ISOK(sc) { // optionally validate against fields in jsonObject w "Hello from Caché server: /csp/portfolio2 application!" w "running code as $username = "_$username_" with following $roles = "_$roles_" at node "_$p($zu(86),"*",2)_"." } } else { w "NOT AUTHORIZED!" w "" w i $d(%objlasterror) d $system.OBJ.DisplayError() w "" } Quit $$$OK } } ### **Alternativa 2 — autenticação delegada** Esse é outro caso extrema, queremos usar a identidade do usuário no servidor de recursos o máximo possível, como se o usuário estivesse trabalhando com o mesmo contexto de segurança que os usuários internos do servidor de recursos. Uma das opções possíveis é usar a autenticação delegada. Para essa definição funcionar, precisamos concluir mais algumas etapas para configurar o servidor de recursos. ·        Ativar a autenticação delegada ·        Fornecer a rotina ZAUTHENTICATE ·        Configurar o Web application (no nosso caso, chamamos em /csp/portfolio) A implementação da rotina ZAUTHENTICATE é bastante simples e direta, já que confiamos no AUTHSERVER que forneceu a identidade do usuário e o escopo (perfil de segurança) dele, então basta aceitar o nome de usuário e transmitir com o escopo ao banco de dados de usuários do servidor de recursos (com a tradução necessária entre o escopo do OAUTH e as funções do InterSystems IRIS). É isso. O resto é realizado perfeitamente pelo InterSystems IRIS. Veja o exemplo de uma rotina ZAUTHENTICATE #include %occErrors #include %occInclude ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) PUBLIC { set tRes=$SYSTEM.Status.OK() try { set Properties("FullName")="OAuth account "_Username //set Properties("Roles")=Credentials("scope") set Properties("Username")=Username //set Properties("Password")=Password // temporary hack as currently we can't pass Credentials array from GetCredentials() method set Properties("Password")="xxx" // we don't really care about oauth2 account password set Properties("Roles")=Password } catch (ex) { set tRes=$SYSTEM.Status.Error($$$AccessDenied) } quit tRes } GetCredentials(ServiceName,Namespace,Username,Password,Credentials) Public { s ts=$zts set tRes=$SYSTEM.Status.Error($$$AccessDenied) try { If ServiceName="%Service_CSP" { set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.sc) if $$$ISOK(sc) { set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection("RESSERVER resource",accessToken,.jsonObject) if $$$ISOK(sc) { // todo: watch out for potential collision between standard account and delegated (openid) one! set Username=jsonObject.username set Credentials("scope")=$p(jsonObject.scope,"openid profile ",2) set Credentials("namespace")=Namespace // temporary hack //set Password="xxx" set Password=$tr(Credentials("scope")," ",",") set tRes=$SYSTEM.Status.OK() } else { set tRes=$SYSTEM.Status.Error($$$GetCredentialsFailed) } } } else { set tRes=$SYSTEM.Status.Error($$$AccessDenied) } } catch (ex) { set tRes=$SYSTEM.Status.Error($$$GetCredentialsFailed) } Quit tRes } A própria página CSP pode ser bastante simples: Class oauth2test.demoResource Extends %CSP.Page { ClassMethod OnPage() As %Status { // access token authentication is performed by means of Delegated authentication! // no need to do it, again, here // This is a dummy resource server which just gets the access token from the request and // uses the introspection endpoint to ensure that the access token is valid. // Normally the response would not be security related, but would contain some interesting // data based on the request parameters. w "Hello from Caché server: /csp/portfolio application!" w "running code as $username = "_$username_" with following $roles = "_$roles_" at node "_$p($zu(86),"*",2)_"." Quit $$$OK } } Por fim, a configuração do Web application para /csp/portfolio ![](/sites/default/files/inline/images/15.png) Se você estiver muito paranoico, pode definir _Classes permitidas_ como fizemos na primeira variante. Ou, novamente, use a API REST. No entanto, isso está muito além do escopo do nosso tema. Na próxima vez, vamos explicar classes individuais, apresentadas pelo framework OAUTH do InterSystems IRIS. Descreveremos as APIs e quando/onde chamá-las.   [1] Quando mencionamos o OAUTH, queremos dizer o OAuth 2.0 conforme especificado no RFC 6749 - . Usamos a abreviação OAUTH apenas por simplicidade. [2] O OpenID Connect é mantido pela OpenID Foundation –
Anúncio
Danusa Calixto · Maio 24, 2023

InterSystems Testing Manager - uma nova extensão do VS Code para a estrutura %UnitTest

Se você já construiu testes unitários utilizando o %UnitTest framework, ou está pensando em usá-lo, por favor dê uma olhada no InterSystems Testing Manager. Agora você pode buscar os testes unitários sem sair do VS Code, executar ou depurá-los, e visualizar os resultados da execução anterior. O InterSystems Testing Manager funciona com ambos os paradigmas de localização de código-fonte suportados pela extensão ObjectScript. Suas classes de teste unitário podem ser dominado no sistema de arquivos local do VS Code (o paradigma 'edição lado cliente') ou em um namespace servidor ('edição lado servidor'). Em ambos os casos a execução real dos testes ocorre em um namespace no servidor. Comentários são bem-vindos.
Artigo
Heloisa Paiva · Mar. 26

Plataformas de Dados e Desempenho da InterSystems – Parte 8: Planejamento de Capacidade e Desempenho de Infraestrutura Hiperconvergente

As soluções de Infraestrutura Hiperconvergente (HCI) têm ganhado força nos últimos anos, com o número de implementações agora aumentando rapidamente. Os tomadores de decisão de TI estão considerando HCI ao planejar novas implementações ou atualizações de hardware, especialmente para aplicações já virtualizadas no VMware. As razões para escolher HCI incluem: lidar com um único fornecedor, interoperabilidade validada entre todos os componentes de hardware e software, alto desempenho, especialmente de IO (entrada/saída), escalabilidade simples pela adição de hosts, implementação simplificada e gerenciamento simplificado. Escrevi este artigo com uma introdução para um leitor que é novo em HCI, analisando os recursos comuns das soluções de HCI. Em seguida, reviso as opções de configuração e recomendações para planejamento de capacidade e desempenho ao implementar aplicativos construídos na plataforma de dados InterSystems, com exemplos específicos para aplicativos de banco de dados. As soluções de HCI dependem do armazenamento flash para desempenho, por isso também incluo uma seção sobre as características e casos de uso de opções selecionadas de armazenamento flash. O planejamento de capacidade e as recomendações de desempenho neste artigo são específicos para o _VMWare vSAN_. No entanto, o vSAN não está sozinho no crescente mercado de HCI; existem outros fornecedores de HCI, notóriamente a _Nutanix_ que também possui um número crescente de implementações. Há muita similaridade entre os recursos, independentemente do fornecedor de HCI escolhido, então espero que as recomendações neste artigo sejam amplamente relevantes. Mas o melhor conselho em todos os casos é discutir as recomendações deste artigo com os fornecedores de HCI, levando em consideração os requisitos específicos de sua aplicação. [Uma lista de outras publicações na série de Plataformas de Dados e desempenho da InterSystems está aqui.](https://community.intersystems.com/post/capacity-planning-and-performance-series-index) # O que é HCI? Estritamente falando, soluções convergentes existem há muito tempo, no entanto, nesta postagem, estou falando sobre as soluções HCI atuais, por exemplo, da [Wikipedia:](https://en.wikipedia.org/wiki/Hyper-converged_infrastructure) "A hiperconvergência se afasta de múltiplos sistemas discretos que são empacotados juntos e evoluem para ambientes inteligentes__ definidos por software__ que todos rodam em __servidores rack x86 de prateleira, de uso geral__...." ## Então, HCI é uma coisa única? Não. Ao conversar com fornecedores, você deve lembrar que o HCI tem muitas permutações; Convergido e hiperconvergido são mais um tipo de arquitetura, não um projeto ou padrão específico. Devido à natureza de commodity do hardware HCI, o mercado tem vários fornecedores se diferenciando na camada de software e/ou outras maneiras inovadoras de combinar computação, rede, armazenamento e gerenciamento. Sem entrar muito em detalhes aqui, como exemplo, soluções rotuladas como HCI podem ter armazenamento dentro dos servidores em um cluster ou ter uma configuração mais tradicional com um cluster de servidores e armazenamento SAN separado – possivelmente de fornecedores diferentes – que também foi testado e validado para interoperabilidade e gerenciado a partir de um único painel de controle. Para planejamento de capacidade e desempenho, você deve considerar que soluções onde o armazenamento está em um array conectado por um fabric SAN (por exemplo, Fibre Channel ou Ethernet) têm um perfil de desempenho e requisitos diferentes do caso em que o pool de armazenamento é definido por software e localizado dentro de cada um dos nós do cluster de servidores com processamento de armazenamento nos servidores. ## Então, o que é HCI novamente? Para esta postagem, estou me concentrando em HCI e especificamente _VMware vSAN_ onde o_armazenamento está fisicamente dentro dos servidores host._. Nessas soluções, a camada de software HCI permite que o armazenamento interno em cada um dos múltiplos nós em um cluster execute o processamento para agir como um sistema de armazenamento compartilhado. Portanto, outro fator impulsionador do HCI é que, mesmo que haja um custo para o software HCI, também pode haver economias significativas ao usar HCI em comparação com soluções que usam arrays de armazenamento corporativos. >Para esta postagem, estou falando sobre soluções onde o HCI combina computação, memória, armazenamento, rede e software de gerenciamento em um cluster de servidores x86 virtualizados. ## Características comuns do HCI Como mencionado acima, _VMWare vSAN_ e _Nutanix_ são exemplos de soluções HCI. Ambos têm abordagens de alto nível semelhantes para HCI e são bons exemplos do formato: - _VMware vSAN_ requer VMware vSphere e está disponível em hardware de vários fornecedores. Existem muitas opções de hardware disponíveis, mas estas são estritamente dependentes da Lista de Compatibilidade de Hardware (HCL) do vSAN da VMware. As soluções podem ser compradas pré-embaladas e pré-configuradas, por exemplo, EMC VxRail, ou você pode comprar componentes na HCL e construir o seu próprio. - _Nutanix_ também pode ser comprado e implantado como uma solução completa, incluindo hardware em blocos pré-configurados com até quatro nós em um appliance 2U. A solução Nutanix também está disponível como uma solução de software para construir o seu próprio, validada no hardware de outros fornecedores. Existem algumas variações na implementação, mas, de modo geral, o HCI possui recursos comuns que informarão seu planejamento de desempenho e capacidade: - Máquinas Virtuais (VMs) são executadas em hypervisors como VMware ESXi, mas também outros, incluindo Hyper-V ou Nutanix Acropolis Hypervisor (AHV). O Nutanix também pode ser implantado usando o ESXi. - Os servidores host são frequentemente combinados em blocos de computação, armazenamento e rede. Por exemplo, um Appliance 2U com quatro nós. - Vários servidores host são combinados em um cluster para gerenciamento e disponibilidade. - O armazenamento é em camadas, totalmente flash ou híbrido com uma camada de cache flash mais discos rígidos como camada de capacidade. - O armazenamento é apresentado como um pool definido por software, incluindo posicionamento de dados e políticas de capacidade, desempenho e disponibilidade. - A capacidade e o desempenho de E/S são escalados adicionando hosts ao cluster. - Os dados são gravados no armazenamento em vários nós do cluster de forma síncrona, para que o cluster possa tolerar falhas de host ou componente sem perda de dados. - A disponibilidade e o balanceamento de carga da VM são fornecidos pelo hypervisor, por exemplo, vMotion, VMware HA e DRS. Como observei acima, também existem outras soluções HCI com variações nesta lista, como suporte para arrays de armazenamento externo, nós somente de armazenamento... a lista é tão longa quanto a lista de fornecedores. A adoção do HCI está ganhando ritmo e a concorrência entre os fornecedores está impulsionando a inovação e as melhorias de desempenho. Também vale a pena notar que o HCI é um bloco de construção básico para a implantação em nuvem. # Os produtos da InterSystems são suportados em HCI? É política e procedimento da InterSystems verificar e lançar os produtos da InterSystems em relação a tipos de processador e sistemas operacionais, inclusive quando os sistemas operacionais são virtualizados. Observe o [Aviso da InterSystems: Data Centers Definidos por Software (SDDC) e Infraestrutura Hiperconvergente (HCI).](https://www.intersystems.com/product-alerts-advisories/advisory-software-defined-data-centers-sddc-and-hyper-converged-infrastructure-hci). Por exemplo: Caché 2016.1 executado no sistema operacional Red Hat 7.2 no vSAN em hosts x86 é suportado. Observação: se você não escrever seus próprios aplicativos, também deverá verificar a política de suporte de seus fornecedores de aplicativos. # Planejamento de capacidade do vSAN Esta seção destaca considerações e recomendações para a implantação do _VMware vSAN_ para aplicações de banco de dados em plataformas de dados InterSystems - Caché, Ensemble e HealthShare. No entanto, você também pode usar essas recomendações como uma lista geral de perguntas de configuração para revisar com qualquer fornecedor de HCI. ## vCPU e memória da VM Como ponto de partida, use as mesmas regras de planejamento de capacidade para a vCPU e a memória de suas VMs de banco de dados que você já usa para implantar seus aplicativos no VMware ESXi com os mesmos processadores. Como um lembrete para o dimensionamento geral de CPU e memória para o Caché, uma lista de outras postagens nesta série está aqui: [Planejamento de capacidade e índice de série de performance.](https://community.intersystems.com/post/capacity-planning-and-performance-series-index) Uma das características dos sistemas HCI (Infraestrutura Hiperconvergente) é a latência de E/S de armazenamento muito baixa e a alta capacidade de IOPS (Operações de Entrada/Saída por Segundo). Você deve se lembrar da segunda postagem desta série, o [ gráfico dos grupos alimentares de hardware](https://dl.dropboxusercontent.com/u/25822386/InterSystems/performance2/foodGroups.png) mostrando CPU, memória, armazenamento e rede. Eu destaquei que esses componentes estão todos relacionados entre si e mudanças em um componente podem afetar outro, às vezes com consequências inesperadas.Por exemplo, vi um caso em que a correção de um gargalo de E/S particularmente ruim em um array de armazenamento fez com que o uso da CPU saltasse para 100%, resultando em uma experiência do usuário ainda pior, pois o sistema estava repentinamente livre para fazer mais trabalho, mas não tinha os recursos de CPU para atender ao aumento da atividade do usuário e da taxa de transferência. Esse efeito é algo a se ter em mente ao planejar seus novos sistemas, se seu modelo de dimensionamento for baseado em métricas de desempenho de hardware menos performático. Mesmo que você esteja atualizando para servidores mais novos com processadores mais recentes, a atividade da VM do seu banco de dados deve ser monitorada de perto, caso você precise redimensionar devido à menor latência de E/S na nova plataforma. Observe também que, conforme detalhado posteriormente, você também terá que considerar o processamento de E/S de armazenamento definido por software ao dimensionar os recursos de CPU e memória do _host físico_. ## Planejamento da capacidade de armazenamento Para entender o planejamento da capacidade de armazenamento e colocar as recomendações de banco de dados em contexto, você deve primeiro entender algumas diferenças básicas entre o vSAN e o armazenamento tradicional do ESXi. Abordarei essas diferenças primeiro e, em seguida, detalharei todas as recomendações de melhores práticas para bancos de dados Caché. ### Modelo de armazenamento vSAN No cerne do vSAN e do HCI em geral está o armazenamento definido por software (SDS). A maneira como os dados são armazenados e gerenciados é muito diferente do uso de um cluster de servidores ESXi e um array de armazenamento compartilhado. Uma das vantagens do HCI é que não existem LUNs (Números de Unidades Lógicas), mas sim pools de armazenamento que são alocados para VMs conforme necessário, com políticas que descrevem as capacidades de disponibilidade, capacidade e desempenho por VMDK (Disco Virtual da Máquina Virtual). Por exemplo; imagine um array de armazenamento tradicional consistindo em prateleiras de discos físicos configurados juntos como grupos de discos ou pools de discos de vários tamanhos, com diferentes números e/ou tipos de discos, dependendo dos requisitos de desempenho e disponibilidade. Os grupos de discos são então apresentados como um número de discos lógicos (volumes de array de armazenamento ou LUNs) que, por sua vez, são apresentados aos hosts ESXi como datastores e formatados como volumes VMFS. As VMs são representadas como arquivos nos datastores. As melhores práticas de banco de dados para disponibilidade e desempenho recomendam, no mínimo, grupos de discos e LUNs separados para banco de dados (acesso aleatório), journals (sequencial) e quaisquer outros (como backups ou sistemas não produtivos, etc.). vSAN é diferente; o armazenamento do vSAN é alocado usando gerenciamento baseado em políticas de armazenamento (SPBM). Políticas podem ser criadas usando combinações de capacidades, incluindo as seguintes (mas existem mais): -Falhas a Tolerar (FTT), que dita o número de cópias redundantes de dados. - Codificação de apagamento (RAID-5 ou RAID-6) para economia de espaço. - Faixas de disco (disk stripes) para desempenho. - Provisionamento de disco espesso (thick) ou fino (thin) (fino por padrão no vSAN). - Outros... VMDKs (discos de VM individuais) são criados a partir do pool de armazenamento vSAN selecionando as políticas apropriadas. Então, em vez de criar grupos de discos e LUNs no array com um conjunto de atributos, você define as capacidades de armazenamento como políticas no vSAN usando SPBM; por exemplo, "Banco de Dados" seria diferente de "Diário (Journal)", ou quaisquer outros que você precise. Você define a capacidade e seleciona a política apropriada quando cria discos para sua VM. Outro conceito chave é que uma VM não é mais um conjunto de arquivos em um datastore VMDK, mas é armazenada como um conjunto de _objetos de armazenamento_. Por exemplo, sua VM de banco de dados será composta por múltiplos objetos e componentes, incluindo os VMDKs, swap, snapshots, etc. O vSAN SDS gerencia toda a mecânica de posicionamento de objetos para atender aos requisitos das políticas que você selecionou. ### Camadas de armazenamento e planejamento de desempenho de E/S (IO) Para garantir alto desempenho, existem duas camadas de armazenamento: - Camada de cache - Deve ser flash de alta resistência. - Camada de capacidade - Flash ou, para usos híbridos, discos rígidos (spinning disks). Como mostrado no gráfico abaixo, o armazenamento é dividido em camadas e grupos de discos. No vSAN 6.5, cada grupo de discos inclui um único dispositivo de cache e até sete discos rígidos ou dispositivos flash. Pode haver até cinco grupos de discos, possivelmente até 35 dispositivos por host. A figura abaixo mostra um cluster vSAN all-flash com quatro hosts, cada host tem dois grupos de discos, cada um com um disco de cache NVMe e três discos de capacidade SATA. _Figura 1. Armazenamento vSAN all-flash mostrando camadas e grupos de discos_ Ao considerar como preencher as camadas e o tipo de flash para as camadas de cache e capacidade, você deve considerar o caminho de E/S; para a menor latência e o máximo desempenho, as escritas vão para a camada de cache, então o software consolida e descarrega as escritas para a camada de capacidade. O uso do cache depende do modelo de implantação, por exemplo, em configurações híbridas do vSAN, 30% da camada de cache é cache de escrita, no caso de all-flash, 100% da camada de cache é cache de escrita -- as leituras são da camada de capacidade flash de baixa latência. Haverá um aumento de desempenho usando all-flash. Com unidades flash de maior capacidade e durabilidade disponíveis hoje, chegou a hora de você considerar se precisa de discos rígidos. O argumento comercial para flash em vez de discos rígidos foi feito nos últimos anos e inclui custo/IOPS muito menor, desempenho (menor latência), maior confiabilidade (sem partes móveis para falhar, menos discos para falhar para IOPS necessários), menor consumo de energia e perfil de calor, menor espaço físico e assim por diante. . Você também se beneficiará de recursos adicionais de HCI, por exemplo, o vSAN só permitirá deduplicação e compressão em configurações all-flash. - **Recomendação:_** Para melhor desempenho e menor TCO, considere all-flash. Para o melhor desempenho, a camada de cache deve ter a menor latência, especialmente para o vSAN, pois há apenas um único dispositivo de cache por grupo de discos. - **Recomendação:_** Se possível, escolha SSDs NVMe para a camada de cache, embora SAS ainda seja adequado. - **Recomendação:_** Escolha dispositivos flash de alta resistência na camada de cache para lidar com alto I/O.. Para SSDs na camada de capacidade, há uma diferença de desempenho insignificante entre SSDs SAS e SATA. Você não precisa incorrer no custo de SSDs NVMe na camada de capacidade para aplicações de banco de dados. No entanto, em todos os casos, certifique-se de que está usando SSDs SATA de classe empresarial com recursos como proteção contra falha de energia. - **Recomendação:_** Escolha SSDs SATA de alta capacidade para a camada de capacidade. - **Recomendação:_** Escolha SSDs empresariais com proteção contra falha de energia. Dependendo do seu cronograma, novas tecnologias como o 3D Xpoint, com IOPS mais altos, menor latência, maior capacidade e maior durabilidade, podem estar disponíveis. Há uma análise do armazenamento flash no final deste post. - **Recomendação:_** Fique atento a novas tecnologias a serem incluídas, como o 3D Xpoint, para as camadas de cache E capacidade. Como mencionei acima, você pode ter até cinco grupos de discos por host e um grupo de discos é composto por um dispositivo flash e até sete dispositivos na camada de capacidade. Você pode ter um único grupo de discos com um dispositivo flash e quanta capacidade precisar, ou vários grupos de discos por host. Existem vantagens em ter vários grupos de discos por host: - Desempenho: Ter vários dispositivos flash nas camadas aumentará os IOPS disponíveis por host. - Domínio de falha: A falha de um disco de cache afeta todo o grupo de discos, embora a disponibilidade seja mantida, pois o vSAN reconstrói automaticamente. Você terá que equilibrar disponibilidade, desempenho e capacidade, mas, em geral, ter vários grupos de discos por host é um bom equilíbrio. - **Recomendação:_**Revise os requisitos de armazenamento, considere vários grupos de discos por host. #### Qual desempenho devo esperar? Um requisito fundamental para uma boa experiência do usuário de aplicativos é a baixa latência de armazenamento; a recomendação usual é que a latência de E/S de leitura do banco de dados deve estar abaixo de 10ms. [Consulte a tabela da Parte 6 desta série aqui para obter detalhes.](https://community.intersystems.com/post/data-platforms-and-performance-part-6-cach%C3%A9-storage-io-profile) Para cargas de trabalho de banco de dados Caché testadas usando a política de armazenamento vSAN padrão e o [utilitário RANREAD](https://community.intersystems.com/post/random-read-io-storage-performance-tool)o Caché, observei E/S de leitura aleatória sustentada de 100% acima de 30K IOPS com menos de 1ms de latência para vSAN all-flash usando SSDs SATA Intel S3610 na camada de capacidade. Considerando que uma regra prática básica para bancos de dados Caché é dimensionar instâncias para [ usar memória para o máximo de E/S de banco de dados possível,](https://community.intersystems.com/post/intersystems-data-platforms-and-performance-part-4-looking-memory) a capacidade de latência e IOPS all-flash deve fornecer ampla margem para a maioria das aplicações. Lembre-se de que os tempos de acesso à memória ainda são ordens de magnitude menores do que até mesmo o armazenamento flash NVMe Como sempre, lembre-se de que seus resultados podem variar; políticas de armazenamento, número de grupos de discos e número e tipo de discos, etc., influenciarão o desempenho, portanto, você deve validar em seus próprios sistemas! ## Planejamento de capacidade e desempenho Você pode calcular a capacidade bruta em TB de um pool de armazenamento vSAN aproximadamente como o tamanho total dos discos na camada de capacidade. Em nossa configuração de exemplo na _figura 1_ há um total de 24 SSDs INTEL S3610 de 1,6 TB: >Capacidade bruta do cluster: 24 x 1.6TB = 38.4 TB No entanto, a capacidade _disponível _ é muito diferente e é onde os cálculos se tornam complexos e dependem das escolhas de configuração; quais políticas são usadas (como FTT, que dita quantas cópias de dados) e também se a deduplicação e a compressão foram ativadas. Vou detalhar políticas selecionadas e discutir suas implicações para capacidade e desempenho, e recomendações para uma _arga de trabalho de banco de dados_. Todas as implementações de ESXi que vejo são compostas por múltiplas VMs; por exemplo, o TrakCare, um sistema de informação de saúde unificado construído na plataforma de informática de saúde da InterSystems, HealthShare, tem em seu núcleo pelo menos um grande (monstruoso) servidor de banco de dados VM que se encaixa absolutamente na descrição de "aplicação crítica de negócios de nível 1". No entanto, uma implementação também inclui combinações de outras VMs de propósito único, como servidores web de produção, servidores de impressão, etc. Bem como VMs de teste, treinamento e outras VMs de não produção. Geralmente, todas implantadas em um único cluster ESXi. Embora eu me concentre nos requisitos de VM de banco de dados, lembre-se de que o SPBM pode ser personalizado por VMDK para todas as suas VMs. ### Deduplicação e Compressão Para vSAN, a deduplicação e a compressão são configurações de liga/desliga em todo o cluster. A deduplicação e a compressão só podem ser ativadas quando você estiver usando uma configuração all-flash. Ambas as funcionalidades são ativadas juntas. À primeira vista, a deduplicação e a compressão parecem ser uma boa ideia - você quer economizar espaço, especialmente se estiver usando dispositivos flash (mais caros) na camada de capacidade. Embora haja economia de espaço com deduplicação e compressão, minha recomendação é que você não habilite esse recurso para clusters com grandes bancos de dados de produção ou onde os dados são constantemente sobrescritos. A deduplicação e a compressão adicionam alguma sobrecarga de processamento no host, talvez na faixa de utilização de CPU de um único dígito percentual, mas essa não é a principal razão para não recomendar para bancos de dados. Em resumo, o vSAN tenta deduplicar dados à medida que são gravados na camada de capacidade dentro do escopo de um único grupo de discos, usando blocos de 4K. Portanto, em nosso exemplo na _figura 1_ os objetos de dados a serem deduplicados teriam que existir na camada de capacidade do mesmo grupo de discos. Não estou convencido de que veremos muita economia nos arquivos de banco de dados Caché, que são basicamente arquivos muito grandes preenchidos com blocos de banco de dados de 8K com ponteiros únicos, conteúdos, etc. Em segundo lugar, o vSAN só tentará compactar blocos duplicados e só considerará os blocos compactados se a compactação atingir 50% ou mais.Se o bloco deduplicado não compactar para 2K, ele será gravado não compactado. Embora possa haver alguma duplicação de sistema operacional ou outros arquivos, _ o benefício real da deduplicação e compressão seria para clusters implantados para VDI_. Outro aviso é o impacto de uma falha (embora rara) de um dispositivo em um grupo de discos em todo o grupo quando a deduplicação e a compressão estão ativadas. Todo o grupo de discos é marcado como "não saudável", o que tem um impacto em todo o cluster: porque o grupo está marcado como não saudável, todos os dados em um grupo de discos serão evacuados desse grupo para outros locais, então o dispositivo deve ser substituído e o vSAN ressincronizará os objetos para reequilibrar. - **Recomendação:_** Para implementações de banco de dados, não habilite a compactação e a deduplicação. >_**Barra Lateral: Espelhamento de banco de dados InterSystems.**_ > Para instâncias de aplicativos de banco de dados Caché de nível 1 de missão crítica que exigem a mais alta disponibilidade, recomendo o [espelhamento de banco de dados síncrono da InterSystems, mesmo quando virtualizado.](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GHA_mirror#GHA_mirror_set_bp_vm) Soluções virtualizadas têm HA (alta disponibilidade) integrada; por exemplo, VMWare HA, no entanto, vantagens adicionais de também usar espelhamento incluem: >- Cópias separadas de dados atualizados. - Failover em segundos (mais rápido do que reiniciar uma VM, depois o sistema operacional e, em seguida, recuperar o Caché). -Failover em caso de falha do aplicativo/Caché (não detectada pelo VMware). >Acho que você percebeu a falha em habilitar a deduplicação quando você tem bancos de dados espelhados no mesmo cluster? Você estará tentando deduplicar seus dados espelhados. Geralmente não é sensato e também é uma sobrecarga de processamento. >Outra consideração ao decidir se espelhar bancos de dados em HCI é a capacidade total de armazenamento necessária. O vSAN fará várias cópias de dados para disponibilidade, e esse armazenamento de dados será dobrado novamente pelo espelhamento. Você precisará ponderar o pequeno aumento incremental no tempo de atividade em relação ao que o VMware HA fornece, contra o custo adicional de armazenamento. >Para o máximo tempo de atividade, você pode criar dois clusters para que cada nó do espelho de banco de dados esteja em um domínio de falha completamente independente. No entanto, observe o total de servidores e a capacidade de armazenamento para fornecer esse nível de tempo de atividade. ## Criptografia Outra consideração é onde você escolhe criptografar os dados em repouso. Você tem várias opções na pilha de E/S, incluindo; - Usando a criptografia do banco de dados Caché (criptografa apenas o banco de dados). - No armazenamento (por exemplo, criptografia de disco de hardware no SSD). A criptografia terá um impacto muito pequeno no desempenho, mas pode ter um grande impacto na capacidade se você optar por habilitar a deduplicação ou a compressão no HCI.Se você optar por deduplicação e/ou compressão, não gostaria de usar a criptografia de banco de dados Caché, pois isso negaria quaisquer ganhos, já que os dados criptografados são aleatórios por design e não comprimem bem. Considere o ponto de proteção ou o risco que eles estão tentando proteger, por exemplo, roubo de arquivo versus roubo de dispositivo. - **Recomendação:_** Criptografe na camada mais baixa possível na pilha de E/S para um nível mínimo de criptografia. No entanto, quanto mais risco você deseja proteger, mova-se mais alto na pilha. ### Falhas a tolerar (FTT) FTT define um requisito para o objeto de armazenamento tolerar pelo menos _n_ falhas simultâneas de host, rede ou disco no cluster e ainda garantir a disponibilidade do objeto. O padrão é _1_ (RAID-1); os objetos de armazenamento da VM (por exemplo, VMDK) são espelhados entre os hosts ESXi. >Portanto, a configuração do vSAN deve conter pelo menos n + 1 réplicas (cópias dos dados), o que também significa que existem 2n + 1 hosts no cluster. Por exemplo, para cumprir a política de um número de falhas a tolerar = 1 , você precisa de três hosts no mínimo em todos os momentos -- mesmo que um host falhe. Portanto, para contabilizar a manutenção ou outros momentos em que um host é retirado do ar, você precisa de quatro hosts. - **Recomendação:_** Um cluster vSAN deve ter um mínimo de quatro hosts para disponibilidade. Observe que também existem exceções; uma configuração de Escritório Remoto de Filial (ROBO) que é projetada para dois hosts e uma VM de testemunha remota. ### Codificação de Apagamento O método de armazenamento padrão no vSAN é RAID-1 -- replicação ou espelhamento de dados. A codificação de apagamento é RAID-5 ou RAID-6 com objetos/componentes de armazenamento distribuídos entre os nós de armazenamento no cluster. O principal benefício da codificação de apagamento é uma melhor eficiência de espaço para o mesmo nível de proteção de dados. Usando o cálculo para FTT na seção anterior como um exemplo; para uma VM tolerar _duas _ falhas usando um RAID-1, deve haver três cópias de objetos de armazenamento, o que significa que um VMDK consumirá 300% do tamanho base do VMDK. O RAID-6 também permite que uma VM tolere duas falhas e consuma apenas 150% do tamanho do VMDK. A escolha aqui é entre desempenho e capacidade. Embora a economia de espaço seja bem-vinda, você deve considerar seus padrões de E/S de banco de dados antes de habilitar a codificação de apagamento. Os benefícios de eficiência de espaço vêm ao preço da amplificação das operações de E/S, que é ainda maior durante os períodos de falha de componentes, portanto, para o melhor desempenho do banco de dados, use RAID-1. - **Recomendação:_** Para bancos de dados de produção, não habilite a codificação de apagamento (erasure coding). Habilite apenas para ambientes de não produção. A codificação de apagamento também impacta o número de hosts necessários em seu cluster. Por exemplo, para RAID-5, você precisa de um mínimo de quatro nós no cluster, e para RAID-6, um mínimo de seis nós. - **Recomendação:_** Considere o custo de hosts adicionais antes de planejar a configuração da codificação de apagamento. ### Striping (Distribuição de Dados) A distribuição de dados (striping) oferece oportunidades para melhorias de desempenho, mas provavelmente só ajudará com configurações híbridas. - **Recomendação:_** Para bases de dados de produção, não habilite o striping. ### Reserva de Espaço de Objeto (provisionamento fino ou espesso) O nome para esta configuração vem do vSAN usar objetos para armazenar componentes de suas VMs (VMDKs, etc.).Por padrão, todas as VMs provisionadas em um datastore vSAN têm reserva de espaço de objeto de 0% (provisionamento fino), o que leva a economia de espaço e também permite que o vSAN tenha mais liberdade para o posicionamento de dados. No entanto, para seus bancos de dados de produção, a melhor prática é usar reserva de 100% (provisionamento espesso), onde o espaço é alocado na criação. Para o vSAN, isso será Lazy Zeroed – onde os zeros são escritos à medida que cada bloco é gravado pela primeira vez. Existem algumas razões para escolher reserva de 100% para bancos de dados de produção; haverá menos atraso quando ocorrerem expansões de banco de dados, e você estará garantindo que o armazenamento estará disponível quando precisar. - **Recomendação:_** Para discos de banco de dados de produção, use reserva de 100%. - **Recomendação:_**Para instâncias de não produção, deixe o armazenamento com provisionamento fino. ### Quando devo ativar os recursos? Geralmente, você pode habilitar os recursos de disponibilidade e economia de espaço após usar os sistemas por algum tempo, ou seja, quando houver VMs e usuários ativos no sistema. No entanto, haverá impacto no desempenho e na capacidade. Réplicas adicionais de dados, além do original, são necessárias, portanto, espaço adicional é exigido enquanto os dados são sincronizados. Minha experiência é que habilitar esses tipos de recursos em clusters com grandes bancos de dados pode levar muito tempo e expor a possibilidade de disponibilidade reduzida. - **Recomendação:_** Dedique tempo antecipadamente para entender e configurar recursos e funcionalidades de armazenamento, como deduplicação e compressão, antes da entrada em produção e definitivamente antes que grandes bancos de dados sejam carregados. Existem outras considerações, como deixar espaço livre para balanceamento de disco, falhas, etc. O ponto é que você terá que levar em conta as recomendações deste post com as escolhas específicas do fornecedor para entender seus requisitos de disco bruto. - **Recomendação:_** Existem muitos recursos e permutações. Calcule seus requisitos totais de capacidade em GB como ponto de partida, revise as recomendações neste post [e com o fornecedor do seu aplicativo] e, em seguida, converse com seu fornecedor de HCI. ## Sobrecarga de processamento de armazenamento Você deve considerar a sobrecarga do processamento de armazenamento nos hosts. O processamento de armazenamento, que de outra forma seria tratado pelos processadores em um array de armazenamento empresarial, agora está sendo computado em cada host do cluster. A quantidade de sobrecarga _por host_ dependerá da carga de trabalho e de quais recursos de armazenamento estão habilitados. Minhas observações com testes básicos que realizei com Caché no vSAN mostram que os requisitos de processamento não são excessivos, especialmente quando você considera o número de núcleos disponíveis nos servidores atuais. A VMware recomenda planejar um uso de CPU do host de 5-10%. O acima pode ser um ponto de partida para dimensionamento, mas _lembre-se de que seus resultados podem variar_ e você precisará confirmar. - **Recomendação:_** Planeje para o pior caso de 10% de utilização da CPU e, em seguida, monitore sua carga de trabalho real. ## Rede Revise os requisitos do fornecedor -- assuma NICs de 10GbE mínimos -- NICs múltiplos para tráfego de armazenamento, gerenciamento (por exemplo, vMotion), etc. Posso dizer por experiência dolorosa que um switch de rede de classe empresarial é necessário para a operação ideal do cluster -- afinal, todas as gravações são enviadas de forma síncrona pela rede para disponibilidade. - **Recomendação:_** Largura de banda de rede comutada de 10GbE mínima para tráfego de armazenamento. NICs múltiplos por host, conforme as melhores práticas. #Visão Geral do Armazenamento Flash O armazenamento flash é um requisito do HCI, por isso é bom revisar onde o armazenamento flash está hoje e para onde está indo no futuro próximo. _A história curta é que, quer você use HCI ou não, se você não estiver implantando seus aplicativos usando armazenamento com flash hoje, é provável que sua próxima compra de armazenamento inclua flash._ ## Armazenamento hoje e amanhã Vamos revisar as capacidades das soluções de armazenamento comumente implantadas e garantir que estamos claros com a terminologia. **Disco rígido** - Velho conhecido. Discos rígidos (HDD) de 7.2, 10K ou 15K com interface SAS ou SATA. Baixo IOPS por disco. Podem ter alta capacidade, mas isso significa que os IOPS por GB estão diminuindo. Para desempenho, os dados são normalmente distribuídos em vários discos para alcançar "IOPS suficientes" com alta capacidade. **Disco SSD - SATA e SAS** - Hoje, o flash é geralmente implantado como SSDs com interface SAS ou SATA usando flash NAND. Também há alguma DRAM no SSD como um buffer de gravação. SSDs empresariais incluem proteção contra perda de energia - em caso de falha de energia, o conteúdo da DRAM é descarregado para a NAND. **Disco SSD - NVMe** - Semelhante ao disco SSD, mas usa o protocolo NVMe (não SAS ou SATA) com flash NAND. A mídia NVMe se conecta via barramento PCI Express (PCIe), permitindo que o sistema se comunique diretamente, sem a sobrecarga de adaptadores de barramento de host e estruturas de armazenamento, resultando em latência muito menor. **Array de Armazenamento** - Arrays Empresariais fornecem proteção e a capacidade de escalar. Hoje em dia, é mais comum que o armazenamento seja um array híbrido ou totalmente flash. Arrays híbridos têm uma camada de cache de flash NAND mais uma ou mais camadas de capacidade usando discos rígidos de 7.2, 10K ou 15K. Arrays NVMe também estão se tornando disponíveis. **NVDIMM de Modo Bloco** - Esses dispositivos estão sendo enviados hoje e são usados quando latências extremamente baixas são necessárias. NVDIMMs são instalados em um socket de memória DDR e fornecem latências em torno de 30ns. Hoje, eles são enviados em módulos de 8GB, portanto, provavelmente não serão usados para aplicativos de banco de dados legados, mas novos aplicativos de scale-out podem aproveitar esse desempenho. **3D XPoint** _Esta é uma tecnologia futura - não disponível em novembro de 2016._ - Desenvolvido pela Micron e Intel. Também conhecido como **Optane** (Intel) e **QuantX** (Micron). - Não estará disponível até pelo menos 2017, mas, comparado ao NAND, promete maior capacidade, >10x mais IOPS, >10x menor latência com resistência extremamente alta e desempenho consistente. - A primeira disponibilidade usará o protocolo NVMe. ## Resistência do Dispositivo SSD A _resistência _ do dispositivo SSD é uma consideração importante ao escolher unidades para camadas de cache e capacidade. A história curta é que o armazenamento flash tem uma vida finita. As células flash em um SSD só podem ser excluídas e reescritas um certo número de vezes (nenhuma restrição se aplica às leituras). O firmware no dispositivo gerencia a distribuição de gravações pela unidade para maximizar a vida útil do SSD. SSDs empresariais também normalmente têm mais capacidade flash real do que a visível para alcançar uma vida útil mais longa (superprovisionados), por exemplo, uma unidade de 800GB pode ter mais de 1TB de flash. A métrica a ser observada e discutida com seu fornecedor de armazenamento é o número total de Gravações de Unidade por Dia (DWPD) garantido por um certo número de anos. Por exemplo; um SSD de 800GB com 1 DWPD por 5 anos pode ter 800GB gravados por dia durante 5 anos. Portanto, quanto maior o DWPD (e anos), maior a resistência. Outra métrica simplesmente muda o cálculo para mostrar dispositivos SSD especificados em Terabytes Gravados (TBW); o mesmo exemplo tem TBW de 1.460 TB (800GB * 365 dias * 5 anos). De qualquer forma, você tem uma ideia da vida útil do SSD com base no seu IO esperado. # Resumo Esta postagem aborda os recursos mais importantes a serem considerados ao implantar HCI e, especificamente, o VMWare vSAN versão 6.5. Existem recursos do vSAN que não abordei, se eu não mencionei um recurso, assuma que você deve usar os padrões. No entanto, se você tiver alguma dúvida ou observação, ficarei feliz em discutir através da seção de comentários. Espero retornar ao HCI em futuras postagens, esta certamente é uma arquitetura que está em ascensão, então espero ver mais clientes da InterSystems implantando em HCI.
Artigo
Davi Massaru Teixeira Muta · Jun. 13, 2023

Integrando e-mail do Outlook com oAuth 2.0 no Intersystems IRIS 2020

#Introdução Neste artigo, vamos explorar como integrar uma conta de e-mail do Outlook Exchange com oAuth 2.0 na plataforma Intersystems IRIS 2020. Embora essa tarefa possa parecer simples. No exemplo explorado, utilizamos o código da versão 2022 (você pode baixar a versão de avaliação) e adaptamos para a versão 2020. Embora seja viável atualizar entre as versões com o instalador IRIS 2022, isso leva semanas de testes antes de fazer a alteração em produtividade. Como a integração não podia esperar, decidimos pegar componentes do IRIS 2022 e copiá-los/adaptá-los para a versão 2020. Para aqueles que não sabem, a Microsoft descontinuou a autenticação básica das contas do Exchange Online (https://learn.microsoft.com/pt-br/lifecycle/announcements/basic-auth-deprecation-exchange-online), dada essa situação, qualquer adaptador de correio de entrada (POP3 no caso do IRIS) ou de saída (SMTP no IRIS) agora requer autenticação OAuth 2.0 (https://learn.microsoft.com/pt-br/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth). Como sabemos, o OAuth é um protocolo de autorização que permite que um aplicativo, neste caso o IRIS, acesse os recursos protegidos de um usuário em um serviço online (como Facebook ou Google), sem precisar compartilhar a senha do usuário. Em vez disso, o usuário autoriza o aplicativo a acessar seus recursos por meio de um token de acesso emitido pelo serviço online. O protocolo OAuth é amplamente utilizado na autenticação e autorização de aplicativos da web e móveis. Ao pesquisar na documentação do IRIS, verificamos que a versão 2022 possui integrações nativas disponíveis para o OAuth. Porem a versão 2020 ainda não possui essas opções disponíveis: #Solução Navegando pelas classes do IRIS 2022, especificamente na versão "IRIS for Windows (x86-64) 2022.1.2 (Build 574U)", encontramos duas classes que continham o código necessário para se conectar com um token de autenticação: **%Net.POP3** e **EnsLib.EMail.InboundAdapter**. Comparamos ambas as versões, entre o IRIS 2020 e o IRIS 2022, e começamos a realizar testes de conexão. Após várias tentativas, conseguimos realizar a integração criando e configurando as seguintes classes: **TEST01.BO.REST.OAUTHTOKEN**: Esta classe é responsável por fazer a solicitação REST para obter o token, neste caso, da Microsoft. Ela é chamada pelo serviço POP3 no método onTask sempre que precisa de um novo token. **TEST01.Email.POP3**: Essa classe é uma cópia da classe %Net.POP3 do IRIS 2020, mas precisamos modificá-la no método ConnectPort e adicionar um novo parâmetro chamado "AccessToken". Além disso, devemos adicionar o código (que pode ser resgatado da própria classe, porém da versão 2022) que utiliza o token para se conectar ao servidor de e-mail. **TEST01.Email.InboundAdapter**: Essa classe é uma cópia do EnsLib.EMail.InboundAdapter, mas precisamos fazer duas modificações. Primeiro, devemos modificar a propriedade MailService para "Property MailServer As TEST01.Email.POP3;". Além disso, precisamos modificar o método onTask para que ele utilize a global que armazena o token necessário para acessar a caixa de correio, token resgatado do serviço REST de autenticação (classe TEST01.BO.REST.OAUTHTOKEN). **TEST01.Email.Service**: Classe do Serviço POP3, essa classe deve ser criada normalmente no Studio com o adaptador EnsLib.EMail.InboundAdapter. Essa classe é responsável por coordenar todos os componentes criados. Devemos alterar o adaptador para TEST01.Email.InboundAdapter e modificar/adicionar o método onTask, que permite atualizar o token caso seja necessário. Para fins deste teste, deixamos um erro forçado "Prueba de Lectura" para não excluir os e-mails da conta do Exchange. Finalmente, conseguimos estabelecer a conexão com a caixa de correio e foi possível processá-los para uso posterior. link do OneDrive com as classes utilizadas: https://profcyc-my.sharepoint.com/personal/tclavero_profcyc_onmicrosoft_com/_layouts/15/onedrive.aspx?id=%2Fpersonal%2Ftclavero%5Fprofcyc%5Fonmicrosoft%5Fcom%2FDocuments%2FArticulos%2FPOP3%20oAuth%2Exml&parent=%2Fpersonal%2Ftclavero%5Fprofcyc%5Fonmicrosoft%5Fcom%2FDocuments%2FArticulos&ga=1 Este arigo é tradução para português de (Integrando correo outlook exchange con oAuth 2.0 en Intersystems IRIS 2020)[https://es.community.intersystems.com/post/integrando-correo-outlook-exchange-con-oauth-20-en-intersystems-iris-2020] Artigo premiado em no "2º Concurso de Artículos Técnicos en Español" https://es.community.intersystems.com/post/segundo-concurso-de-art%C3%ADculos-t%C3%A9cnicos-en-espa%C3%B1ol Não foi possível adicionar a referencia a https://es.community.intersystems.com/post/integrando-correo-outlook-exchange-con-oauth-20-en-intersystems-iris-2020 em Link para o post anterior, não deixe de conferir a versão original do artigo.
Artigo
Evgeny Shvarov · Out. 26, 2020

Trabalhando com vários projetos ObjectScript simultâneos utilizando VSCode e Docker no InterSystems IRIS

Olá, desenvolvedores! "objectscript.conn" :{ "ns": "IRISAPP", "active": true, "docker-compose": { "service": "iris", "internalPort": 52773 } Quero compartilhar com vocês um novo recurso bem maneiro que descobri no novo lançamento 0.8 do plugin [VSCode ObjectScript](https://openexchange.intersystems.com/package/VSCode-ObjectScript) de @Dmitry.Maslennikov e CaretDev. O lançamento traz uma nova configuração "docker-compose", que resolve o problema com as portas necessárias para fazer o VSCode Editor se conectar à IRIS. Não era muito conveniente se você tivesse mais de um contêiner Docker com a IRIS em execução na mesma máquina. Agora, esse problema foi resolvido! Veja abaixo como funciona. O conceito de usar o Docker localmente para desenvolvimento com a IRIS  pressupõe que você tem o dockerfile e o docker-compose.yml no repositório usado para compilar o ambiente do projeto e carregar todo o código ObjectScript no contêiner IRIS obtido pelo Docker Hub. Além disso, você tem o arquivo .vscode/settings.json do VSCode no repositório ao qual você aponta a porta de conexão do servidor web IRIS (junto com outras configurações de conexão, como URL, Namespace e credenciais de login). A pergunta é: qual é a porta à qual o VSCode deve se conectar? Você pode usar a porta 52773, que é a porta IRIS padrão para servidores web. Mas, se você tentar iniciar o segundo contêiner do Docker, haverá uma falha, pois você não pode executar dois contêineres do Docker na mesma máquina que esperam conexões pela mesma porta. Mas você pode expor uma porta externa para o contêiner do Docker, e isso pode ser configurado por um arquivo docker-compose.yml. Veja um exemplo (a porta mapeada está em negrito): version: '3.6' services: iris: build: . restart: always ports: - 52791:52773 volumes: - ~/iris.key:/usr/irissys/mgr/iris.key - ./:/irisdev/app No docker-compose, você deve inserir a mesma porta em .vscode/settings.json: Mas qual é o problema? O problema é que, quando você expõe seu projeto como uma biblioteca ou demonstração e convida pessoas a executar e editar o código com o VSCode, você não quer que elas configurem a porta manualmente e quer que elas clonem o repositório, executem o Docker e tenham a opção de colaborar imediatamente. Eis a pergunta: no docker-compose, a que você deve mapear seu projeto para que não haja conflito com o ambiente de outra pessoa? Mesmo se você não o expuser a ninguém exceto você mesmo, que porta deve colocar nas configurações de conexão do .vscode/settings.json? A resposta é: quando você inicia um novo Docker com a IRIS, é exibida a mensagem de erro dizendo que a porta já está sendo usada e que você deve interromper os outros contêineres ou inventar uma nova porta que provavelmente não esteja em uso e tentar usá-la no docker-compose e settings.json. Que chatice! É uma operação inútil que gasta tempo demais. Ninguém gosta de fazer isso. O mesmo ocorre se você expuser a biblioteca. O alívio chegou com o [novo lançamento 0.8 do VSCode ObjectScript](https://openexchange.intersystems.com/package/VSCode-ObjectScript), em que você pode incluir uma seção docker-compose, que resolve o problema para sempre: "objectscript.conn" :{ "ns": "IRISAPP", "active": true, "docker-compose": { "service": "iris", "internalPort": 52773 } A seção contém os parâmetros "service" e "internalPort", que informam ao VSCode que, para encontrar a porta de conexão, deve-se verificar o arquivo docker-compose.yml que temos no mesmo repositório, encontrar "iris" na seção "service" e obter a porta, mapeada para a porta interna 52773. Viva! O mais maneiro é que agora o Docker tem o modo para docker-compose.yml em que você pode não configurar nenhuma porta no Docker. Você pode deixar o símbolo "-" na porta mapeada, e o Docker usará uma porta disponível aleatoriamente.  iris: build: context: . dockerfile: Dockerfile-zpm restart: always ports: - 51773 - 52773 - 53773 volumes: - ~/iris.key:/usr/irissys/mgr/iris.key - ./:/irisdev/app Viva de novo! Agora, você tem uma opção para não se preocupar mais com as portas do servidor web da IRIS às quais o VSCode se conecta. Como funciona nesse caso: executamos o docker-compose.yml, o Docker escolhe uma porta aleatória do servidor web e executa a IRIS com ela, o VSCode obtém essa porta pelo Docker e conecta-se à IRIS por ela, e você pode editar e compilar o código imediatamente. Sem nenhuma configuração adicional. Não tem nada melhor que isso! E você pode fazer o mesmo com [o seguinte modelo](https://openexchange.intersystems.com/package/objectscript-docker-template) que enviei recentemente de acordo com o novo recurso do VSCode ObjectScript 0.8, que atualizou o [settings.json](https://github.com/intersystems-community/objectscript-docker-template/blob/master/.vscode/settings.json) e o [docker-compose.yml](https://github.com/intersystems-community/objectscript-docker-template/blob/master/docker-compose.yml). Para testar o modelo, execute os comandos abaixo no terminal (testados no Mac). Você também precisa do [git](https://git-scm.com/) e do [Docker Desktop](https://www.docker.com/products/docker-desktop) instalados.  $ git clone https://github.com/intersystems-community/objectscript-docker-template.git $ cd objectscript-docker-template $ docker-compose up -d Abra essa pasta no VSCode (é preciso ter o plugin [VScode ObjectScript](https://openexchange.intersystems.com/package/VSCode-ObjectScript) instalado): Verifique se o VSCode está conectado – clique na linha de status do VSCode: ![](/sites/default/files/inline/images/images/screenshot_2020-01-25_16_07_30.png) Reconecte o VSCode, se necessário. Você pode abrir o IRIS Terminal no VSCode, se necessário, com o menu ObjectScript. Concluído! Agora, você pode executar, compilar e depurar o código! Viva a programação!
Anúncio
Angelo Bruno Braga · Mar. 29, 2021

Webinar em inglês : InterSystems IRIS & roadmap da Indústria 4.0 - Smart Factory Starter Pack

Olá desenvolvedores, É um prazer anunciar o próximo webinar em Inglês chamado "InterSystems IRIS & roadmap da Indústria 4.0- Smart Factory Starter Pack"! 🗓 Data & horário: 31 de Março de 2021, 09:00 horário de Brasília 🗣 Palestrantes: @Marco.denHartog, CTO, ITvisors @Aldo.Verlinde9118, Sales Engineer, InterSystems As organizações de manufatura hoje estão transformando rapidamente suas fábricas existentes em "fábricas inteligentes". Em uma fábrica inteligente, os dados dos sistemas de Tecnologias Operacionais (TO) e os sinais em tempo real do chão de fábrica são combinados com os aplicativos empresariais de TI e analíticos. Isso permite que os fabricantes melhorem a qualidade e a eficiência, respondam mais rapidamente aos eventos e prevejam e evitem problemas antes que eles ocorram, entre muitos outros benefícios. Neste webinar, discutimos os 5 níveis de maturidade em relação à Indústria 4.0 de um ponto de vista baseado em dados e como o IRIS e o Smart Factory Starter Pack estão ajudando os fabricantes em cada nível: Coleta de dados: conexões fáceis para muitos tipos diferentes de fontes Unificação de dados: dados limpos, gerenciamento de dados, preenchendo a lacuna de TO / TI, ... Exploração de dados: variedade de ferramentas, conectividade (!), Banco de dados translítico, ... Operacionalização: Minimize a sobrecarga e os erros do operador, conexões bidirecionais (ERP, MES, fluxo de pedidos), banco de dados flexível e fácil de usar, ... Indústria 4.0: Modelagem de processos e equipamentos de produção, previsão de qualidade e desempenho, ciclo de melhoria contínua Descubra como o IRIS e o Smart Factory Starter Pack capacitam os fabricantes em suas iniciativas de fábrica inteligente Observação: O idioma do webinar é Inglês. ➡️ JUNTE-SE AO WEBINAR!
Artigo
Fernando Ferreira · Fev. 3, 2022

Migrando para InterSystems IRIS – Parte 02 (Instância única de Caché/Ensemble para IRIS)

Migrando para InterSystems IRIS – Parte 02 (Instância única de Caché/Ensemble para IRIS) Olá, comunidade, nessa segunda parte do artigo vou dar dicas do processo de migração de uma instância única de InterSystems Caché e ou Ensemble para IRIS. Como comentado na 1ª parte do artigo, a ideia é passar dicas e não substituir os documentos oficiais que estão disponíveis no WRC, que são eles: InterSystems IRIS Adoption Guide; How to migrate to InterSystems IRIS. Vamos então agora colocar a mão na massa! O sistema operacional que estou usando como exemplo, é uma instalação em um ambiente Ubuntu: A instalação do Ensemble é a 2018.1.5: E nesta parte do artigo vamos tratar de uma instalação de única instância sem Mirror, Shadow ou ECP. Essa segunda parte vale ressaltar duas situações que podemos passar: 1º - Instalação do IRIS na mesma máquina onde se encontra o Caché ou Ensemble; 2º - Instalação do IRIS em uma nova máquina. Para ambos os cenários: consultar os pré-requisitos mencionados na primeira parte do artigo. Mas antes de entrar nas sessões aqui uma primeira dica válida para ambas as sessões: BACKUP / BACKUP / BACKUP / BACKUP / BACKUP / BACKUP / BACKUP / BACKUP / BACKUP Antes de iniciar quaisquer procedimentos de migração, a outra dica é execute em: AMBIENTE DE TESTE / AMBIENTE DE TESTE / AMBIENTE DE TESTE / AMBIENTE DE TESTE Queria me desculpar por repetir a palavra BACKUP e AMBIENTES DE TESTE, em caixa alta, mas essa dica é a mais primordial, quem nunca precisou de um backup em um momento tenso e alguém acabou esquecendo-o, que jogue a primeira pedra. Uma outra pergunta recorrente de clientes: Quais Releases Caché e Ensemble são suportadas para migrar o IRIS? No documento oficial que você pode executar o download através do WRC: “How to Migrate to InterSystems IRIS” existe um tópico chamado: “Supported Migration Paths”, neste tópico existe uma matriz da versão origem e qual versão destino do IRIS são compatíveis, um exemplo: No mesmo documento “How to Migrate to InterSystems IRIS” existe um tópico chamado: “Performing Pre-Migration Tasks”, a leitura deste tópico eu diria que é mandatório. Mas vamos lá, como podemos encontrar duas situações vou exemplificar ambas nesta parte do artigo em duas sessões: 1 – Sessão: Instalação do IRIS na mesma máquina onde se encontra o Caché ou Ensemble. No exemplo estou utilizando o usuário root, pois estou em um ambiente de laboratório. Lembre-se, de usar o sudo para execução dos comandos que necessitem de permissões root. Ambiente exemplo: Podem perceber que estou com uma instância que se chama: ENSEMBLE. Os passos que vou exemplificar aqui valem tanto para Caché ou Ensemble, salvo quando vamos falar de parar a Produção do Ensemble. O primeiro passo para ambientes Ensemble é desativar o início automático da Produção: O próximo passo é desligar a produção: Uma dica importante: caso você possua mais de uma produção, lembre-se que você pode para todas as produções via terminal: Agora vamos parar o Ensemble ou Caché com segurança: Lembre-se de passar o nome da instância, no nosso exemplo a instância se chama ENSEMBLE: Importante verificar o ccconsole.log se não ocorreu nenhum problema durante o shutdown: Reparem que as mensagens do Journal estão OK! Agora vamos executar o instalador do IRIS. Lembre-se que você precisa ter permissão de root nesta etapa, ou executar com sudo. No diretório onde você extraiu o kit de instalação, execute: irisinstall Vocês podem observar que ao executar o comando de instalação já foi identificado a nossa instância do Ensemble. Nesta opção vamos adicionar o nome da instância, que no caso do nosso exemplo é ENSEMBLE. Ao digitar o nome da instância, o instalador questionará sobre a atualização para IRIS: E olha aqui novamente a mensagem importantíssima: Você já tem BACKUP? Caso já tenha feito o Backup, vamos pressionar YES e seguir com a instalação. Após pressionar YES, o instalador questionará sobre a licença do IRIS: Lembre-se de informar o path correto, mais o nome da licença: Após a licença ser validada, agora é só pressionar YES para iniciar a conversão! Pronto! Processo de conversão finalizada: Você pode verificar aqui uma primeira mudança de comando, ao invés de utilizar o ccontrol list, agora você executará o iris list para verificar a instância. Vocês podem reparar que o nome da instância, local da instalação e portas são os mesmos, e que a instancia já está no ar. Eu utilizei de propósito o nome da minha instalação de ENSEMBLE para evidenciar que quando executamos a instalação na mesma máquina o instalador mantém todas as características da instalação corrente. Acessando a URL que você já estava acostumado a acessar, você pode entrar no portal do IRIS: O ambiente ainda não está pronto para ser liberado para os usuários! Agora você precisa revisar o seu código, mas como você seguiu as dicas iniciais você já leu o IRIS Migration Guide, e já tem mapeado o que foi deprecado ou renomeado para que você atualize seu código. Agora com o código revisado, vamos recompilar tudo! Lembre-se que você precisa executar esta etapa em todos namespace. Primeiro vamos compilar as rotinas. Lembre-se que você pode compilar as rotinas pelo portal ou pelo terminal. Portal: Terminal: Aqui você pode compilar por namespace: Um exemplo de erros que podem ocorrer durante a compilação das rotinas. Neste caso recebemos um PROTECT, ou seja, são rotinas que estão em READ ONLY, e são rotinas padrões do sistema, neste caso não temos com o que se preocupar. Também é possível executar a compilação de todas as rotinas em todos namespaces, executando: do ##Class(%Routine).CompileAllNamespaces() Agora vamos compilar as classes, como as rotinas podemos compilar pelo portal ou terminal: Portal: Terminal: Para as classes também é possível compilar por namespace ou todos os namepaces: Caso sua aplicação possua CSP pages, elas precisam ser recarregadas e compiladas. Lembre-se que você precisa mudar o namespace e passar o diretório de onde se encontram as CSP Pages. Pronto agora é testar sua aplicação: Nesta primeira sessão executamos a instalação no mesmo servidor, agora vamos para a próxima sessão deste artigo: 2 – Sessão: Instalação do IRIS em uma nova máquina. A Instalação do IRIS em uma nova máquina irei publicar em um outro artigo, como continuação deste.
Anúncio
Angelo Bruno Braga · Ago. 1, 2022

[Vídeo] Introdução às Integrações HL7 V2 no InterSystems IRIS for Health

Olá Desenvolvedores, Aprendam o básico do gerenciamento de mensagens HL7® V2 no InterSystems IRIS for Health™: ⏯ Introdução a Integrações HL7 V2 no InterSystems IRIS for Health Curtam no Canal de Desenvolvedores InterSystems no YouTube e fique ligado!
Artigo
Danusa Calixto · Set. 12, 2022

Benefícios da Análise Adaptativa com a tecnologia do AtScale + InterSystems Report Designer com a tecnologia do Logi Reports

O AtScale extrai dados da base IRIS.  O produto AtScale forma um cubo OLAP virtual na camada intermediária, que pode ser acessado pelos aplicativos externos usando a linguagem padrão SQL e MDX (Expressões Multidimensionais). A solução inclui três componentes principais. O Design Center é usado para projetar cubos OLAP, formando links entre os metadados e as dimensões de um cubo virtual. Junto com a tarefa de criar um esquema de dados, os problemas da política de acesso a determinados dados e segurança são resolvidos aqui. Como o Cubo Virtual não armazena Big Data fisicamente, garantir um desempenho aceitável é um problema sério.  ![](https://lh3.googleusercontent.com/yUPGBQ-rgdrnz6ALaHFyfp5GyFY-uDN18mrStZDpc4MfmEJUHVQ_BDaXy59cxehC9oaZOyDgI5UD_Wz2H_p-rPtFxU3ILqHFxwbL3gooRp2sC8veShm1_IV_zfnKt8xQFO1lNfCLul1Mza7b98rdHhM) O Cache Adaptável possibilita não só armazenar em cache os dados recentes ou usados com frequência, mas também prever quais dados serão necessários em breve para a pré-busca no cache. Para conectar o Logi ao AtScale, use o tipo de conexão JDBC Hive2 com o driver org.apache.hive.jdbc.HiveDriver. A vantagem desse tipo de conexão é a adição de um número ilimitado de cubos a um Catálogo. Isso possibilita criar relatórios complexos com um grande conjunto de dados. Além disso, é possível criar um diagrama dentro do Logi com base em cubos e criar links entre cubos do AtScale, o que amplia as possibilidades de geração de dados. Também é possível criar consultas SQL para cubos manualmente. Esse recurso não é usado com frequência, mas pode ser empregado para estabelecer relações manualmente ou projetar fórmulas SQL. ![](https://lh3.googleusercontent.com/jP5wJV5PqGS86UDDJNMOboGZEYeERKHHZ24fX-fAIo_NQZvtGs9QUIIfgeAiRq3_0KV3wlh_WaLXaUzIHtpYyiVGTBtjH41soX9ujNM9UDr1OylDgs3TKQy2c3dJLOipgPz8OnvL6ZpkZeu0ET5nDpE) A maior parte da lógica para a geração de um conjunto de dados ocorre no lado do AtScale. O Logi (InterSystems Report Designer) aceita os conjuntos de dados gerados e visualiza esses dados. Conjunto de dados de teste do aplicativo Sales Insights (versões do AtScale >= 2019.2.x) "Ganhe insights sobre as tendências de vendas, o desempenho dos produtos e os detalhes dos clientes usando estes dados de amostra baseados no conjunto de dados do AdventureWorks." Ele pode ser baixado no link ![](https://lh5.googleusercontent.com/aei99Sj-qiYH4u9TcCJtOC4MOr4T9OexyLxyrSkYksA4p7jCM4XUTV_83EjDObhk6NDgnA5of6bkZ015SNUiSrPiMwwNnfcllFslebmYS6FOa0mY8RoCb1194GlgEQHiSFmE-9lfkqz0MTMy5U4qX7g) Veja como esse conjunto de dados aparece no InterSystems Reports Designer ![](https://lh3.googleusercontent.com/0h70_1dktp8jZn4aUIzRlt1Rg3hA8-P275jl4onq0v8GX_U8tSnfQwcbHAfcSMB-cY4IY-kSRHh-uZMgzDKufPbSMpLr2g2uZvP09OcUHZyU7FkPI_zqSF7IfrzUrGQIGz4UkdyckGP8isDJB-Rat7c) ### As principais vantagens que ganhamos ao usar esse pacote são: Possibilidade de geração automática de relatórios de acordo com a programação Opção de receber relatórios em PDF por e-mail Oportunidade de usar parâmetros automaticamente calculados para o relatório (datas) Aceleração da geração de relatórios (UDAF, agregados e caching) Capacidade de clonar, fazer backup e rapidamente propagar as mudanças no cubo do AtScale Extensão de funcionalidade do Logi: alguns dos parâmetros comparativos não eram calculados no Logi e DeepSee anteriormente Substituição da funcionalidade do Logi: cálculo dos indicadores comparativos dependendo das configurações de parâmetro no lado do AtScale ## Por que o UDAF é necessário para a Análise Adaptativa e como configurá-lo A Análise Adaptativa da InterSystems (com a tecnologia do AtScale) é um complemento poderoso ao BI do IRIS. Ela permite aos usuários o desenvolvimento mais rápido de painéis. Além disso, os responsáveis pelo desenvolvimento e pela manutenção podem alternar rapidamente entre as origens de dados. Por último, mas não menos importante, são os instantâneos das versões dos cubos de dados. Eles oferecem a capacidade de fazer backup da lógica de estrutura de dados e reverter, se necessário. Algumas das funções já estão prontas para uso. No entanto, uma opção importante precisa ser configurada. Refiro-me à opção que aumenta a velocidade dos Painéis e Relatórios. Ela é chamada de UDAF. Sem a configuração, você não verá a otimização ou melhoria do mecanismo de camada de abstração. Você pode acessar a distribuição do UDAF no mesmo local que a Análise Adaptativa. ### O UDAF oferece à análise adaptativa duas principais vantagens:  - a capacidade de armazenar os resultados da execução de consultas (chamadas de Tabelas Agregadas), para que a próxima consulta, usando a agregação de dados, possa usar resultados já calculados do banco de dados. - a capacidade de usar funções adicionais (como Funções Agregadas Definidas pelo Usuário) e algoritmos de processamento de dados que a Análise Adaptativa é forçada a armazenar na origem dos dados.  Eles são armazenados no banco de dados em tabelas separadas, e a Análise Adaptativa pode chamá-los pelo nome em consultas geradas automaticamente. Quando a Análise Adaptativa usa essas funções, a velocidade das consultas aumenta. O local onde todas essas tabelas serão armazenadas é especificado ao criar uma conexão ao IRIS no item AGGREGATE SCHEMA. Se esse esquema não existir no banco de dados, ele será criado. É uma boa ideia armazenar esse esquema em outro banco de dados. Explicarei o motivo disso depois. ![](https://lh6.googleusercontent.com/zbHIWXgl__bTTWIvUGMKIpHIx5b1t7-_fyCy9y69zdcKI6o_PUqUR5S-X9aOePyio1m7sTQvawsWeiXo7rj57kW0JZOxkFc7SlIlMHeKoAYWLN2E3kbzAslFziML48hN53JGhGVWaiWDqGsT3MeXFjY) Agora, imagine que o IRIS, conectado à análise adaptativa, é destinado somente para análise e contém apenas uma cópia dos dados de um banco de dados em execução (para que as solicitações dos sistemas analíticos não carreguem os recursos do banco de dados principal). Após determinado tempo, os dados do sistema principal são copiados para nosso IRIS, substituindo os dados antigos. Nesse caso, no momento da reescrita, todos os dados registrados pela Análise Adaptativa desaparecem, e temos o seguinte resultado: - as consultas que estão tentando acessar as tabelas agregadas não as acham e acabam com um erro. - as solicitações que usam as funções armazenadas no banco de dados não conseguem acessá-las e acabam com um erro. - ao excluir caminhos antigos para agregar tabelas, a Análise Adaptativa discretamente cria novos, e depois a situação repete-se. O descrito acima é apenas um dos casos possíveis de substituição de dados no IRIS, mas nem por isso é o mais comum. O principal problema é que a Análise Adaptativa não usa mecanismos de fallback ao evitar usar opções de UDAF e criar consultas diretas no caso de erros. Ela falha em informar atualizações de painéis ou desenvolvimento.  Podemos tentar carregar a tabela com as funções na base de dados e as atualizações manualmente. No entanto, conforme mencionado acima, UDAF não é somente as funções de processamento de dados, mas também as tabelas agregadas, e salvá-las novamente é bastante problemático. A solução para os problemas descritos acima é a criação de uma tabela de dados separada, em que a Análise Adaptativa escreverá as tabelas do serviço. Essa solução é descrita na documentação para conectar a Análise Adaptativa ao IRIS: Vale a pena mencionar que o nome do esquema especificado após "/<instancePath>/mgr/" precisa corresponder ao especificado como AGGREGATE SCHEMA com a Análise Adaptativa. Caso contrário, uma base de dados separada será criada, mas a Análise Adaptativa escreverá os dados para o esquema criado dentro da base de dados, ignorando a base separada recém-criada. Os desenvolvedores de UDAF recomendam usar "AtScale" como o nome desse esquema. É também o nome dado como exemplo na documentação. Caso esse banco de dados seja corrompido e os dados não possam ser recuperados, você pode desativar as agregações na Análise Adaptativa para recriá-los automaticamente na próxima solicitação. ![](https://lh3.googleusercontent.com/LZq9N4LS9Vfkb6zoJX2o1qh4Tu4pgTp5PPQ8iM7lQIaTfUX_0-o2GHI81jc8cksMIicor5i5NcQcwuw2LJo5h3ArHwyNNp11_Ni-9XdpNr1eOUcn3g5kAC1y1NuSa8bowz4K-0dWPoTc40MgDi-hF3o) Para fazer isso, na guia de agregados/instâncias, você precisa desativar cada agregado. São exibidos 20 agregados por página, então acesse cada página para verificar se todos estão desativados. Se você for usar a Análise Adaptativa, preste atenção nesse pequeno ponto. No início do meu trabalho com a Análise Adaptativa, essa opção foi configurada com um erro, então não tive todos os benefícios possíveis. Lembre-se também de conferir o nome da base de dados. Ela diferencia maiúsculas de minúsculas na configuração e no script da instalação de UDAF. Acredito que talvez haja algumas opções que desconheço no momento, assim como a influência no desempenho dos meus sistemas analíticos. Se você encontrar algo, escreva nos comentários. 
Anúncio
Angelo Bruno Braga · Out. 19, 2022

Segunda Mesa Redonda da Comunidade: Qual é o melhor sistema de controle de fontes para desenvolvimento com InterSystems IRIS

Olá Comunidade, Vamos nos encontrar virtualmente na nossa Segunda Mesa Redonda da Comunidade!Esta será uma discussão envolvente de 45 minutos sobre um tópico específico: Qual é o melhor sistema de controle de fontes para desenvolvimento com InterSystems IRIS. >> Inscreva-se aqui << Palestrante: @Evgeny.Shvarov Co-palestrantes: @Dmitry.Maslennikov and @Timothy.Leavitt 📅 Data: 27 Outubro🕑 Horário: 10:00 horário de Brasília >> Inscreva-se aqui <<Você tem perguntas específicas sobre o tópico que será discutido na mesa redonda? Por favor compartilhe-os nos comentários!
Artigo
Danusa Calixto · Fev. 23, 2023

Entrega contínua de sua solução InterSystems usando GitLab – Parte VIII: CD usando ICM

[Nesta série de artigos](https://pt.community.intersystems.com/post/entrega-contínua-de-sua-solução-intersystems-usando-gitlab-–-índice), quero apresentar e discutir várias abordagens possíveis para o desenvolvimento de software com tecnologias da InterSystems e do GitLab. Vou cobrir tópicos como: * Git básico * Fluxo Git (processo de desenvolvimento) * Instalação do GitLab * Fluxo de trabalho do GitLab * Entrega contínua * Instalação e configuração do GitLab * CI/CD do GitLab * Por que contêineres? * Infraestrutura dos contêineres * CD usando contêineres * **CD usando ICM** Neste artigo, vamos desenvolver a entrega contínua com o InterSystems Cloud Manager. O ICM é uma solução de provisionamento e implantação na nuvem para aplicativos baseados no InterSystems IRIS. Ele permite definir a configuração de implantação desejada e o ICM provisiona de maneira automática. Para mais informações, consulte [First Look: ICM](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_icm). Fluxo de trabalho Na nossa configuração de entrega contínua: * Enviamos código para o repositório do GitLab * Criamos a imagem docker * Publicamos a imagem no registro docker * Testamos em um servidor de teste * Se os testes forem aprovados, implantamos em um servidor de produção Ou em formato gráfico: Como você pode ver, é praticamente igual, exceto que usaríamos o ICM em vez de gerenciar os contêineres do Docker manualmente. ## Configuração do ICM Antes de atualizar os contêineres, eles devem ser provisionados. Para isso precisamos definir defaults.json e definitions.json, descrevendo nossa arquitetura. Vou fornecer esses 2 arquivos para um servidor LIVE, as definições para um servidor TEST são as mesmas, e os padrões são os mesmos, exceto para os valores Tag e SystemMode. #### defaults.json: { "Provider": "GCP", "Label": "gsdemo2", "Tag": "LIVE", "SystemMode": "LIVE", "DataVolumeSize": "10", "SSHUser": "sample", "SSHPublicKey": "/icmdata/ssh/insecure.pub", "SSHPrivateKey": "/icmdata/ssh/insecure", "DockerImage": "eduard93/icmdemo:master", "DockerUsername": "eduard93", "DockerPassword": "...", "TLSKeyDir": "/icmdata/tls", "Credentials": "/icmdata/gcp.json", "Project": "elebedyu-test", "MachineType": "n1-standard-1", "Region": "us-east1", "Zone": "us-east1-b", "Image": "rhel-cloud/rhel-7-v20170719", "ISCPassword": "SYS", "Mirror": "false" } #### definitions.json [ { "Role": "DM", "Count": "1", "ISCLicense": "/icmdata/iris.key" } ] Dentro do contêiner ICM, a pasta /icmdata é montada a partir do host e: * As definições do servidor TEST são colocadas na pasta /icmdata/test * As definições do servidor LIVE são colocadas na pasta /icmdata/live Depois de obter todas as chaves necessárias: keygenSSH.sh /icmdata/ssh keygenTLS.sh /icmdata/tls E colocar os arquivos necessários em /icmdata: * iris.key * gcp.json (para a implantação no Google Cloud Platform) Chame o ICM para provisionar suas instâncias: cd /icmdata/test icm provision icm run cd /icmdata/live icm provision icm run Um servidor TEST e um servidor LIVE seriam provisionados com uma instância do InterSystems IRIS independente em cada um. Consulte [ICM First Look](http://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_icm) para ver um guia mais detalhado. Criação Primeiro, precisamos criar nossa imagem. Nosso código seria, como sempre, armazenado no repositório, a configuração de CD em gitlab-ci.yml. No entanto, além disso (para aumentar a segurança), armazenaríamos vários arquivos específicos do servidor em um servidor de compilação. #### iris.key Chave de licença. Como alternativa, ela pode ser baixada durante a compilação do contêiner em vez de armazenada em um servidor. É bastante arriscado armazenar no repositório. pwd.txt Arquivo contendo a senha padrão. Novamente, é bastante arriscado armazená-lo no repositório. Além disso, se você estiver hospedando um ambiente de produção em um servidor separado, ele poderá ter uma senha padrão diferente. load_ci_icm.script O script inicial: * Carrega o instalador * O instalador inicializa o aplicativo * Carrega o código set dir = ##class(%File).NormalizeDirectory($system.Util.GetEnviron("CI_PROJECT_DIR")) do ##class(%SYSTEM.OBJ).Load(dir _ "Installer/Global.cls","cdk") do ##class(Installer.Global).init() halt Observe que a primeira linha é deixada em branco de maneira intencional. Várias coisas diferem dos exemplos anteriores. Em primeiro lugar, não habilitamos a autenticação do SO, pois o ICM interagiria com o contêiner em vez do GitLab diretamente. Segundo, estou usando o manifesto do instalador para inicializar nosso aplicativo para mostrar diferentes abordagens de inicialização. Leia mais sobre o Instalador [neste artigo](https://community.intersystems.com/post/deploying-applications-intersystems-cache-installer). Por fim, publicaremos nossa imagem em um Docher Hub como um repositório privado. ####   #### Installer/Global.cls Nosso manifesto do instalador fica desta forma: E implementa as seguintes mudanças: 1. Cria o namespace do aplicativo. 2. Cria o banco de dados de código do aplicativo (os dados seriam armazenados no banco de dados USER). 3. carrega o código no banco de dados de código do aplicativo. 4. Mapeia o pacote MyApp para o namespace USER. 5. Cria dois aplicativos para a Web: para HTML e para REST. gitlab-ci.yml Agora, para a configuração da entrega contínua: build image: stage: build tags: - master script: - cp -r /InterSystems/mount ci - cd ci - echo 'SuperUser' | cat - pwd.txt load_ci_icm.script > temp.txt - mv temp.txt load_ci.script - cd .. - docker build --build-arg CI_PROJECT_DIR=$CI_PROJECT_DIR -t eduard93/icmdemo:$CI_COMMIT_REF_NAME . O que está acontecendo aqui? Primeiro, como o [docker build](https://docs.docker.com/engine/reference/commandline/build/) pode acessar apenas subdiretórios de um diretório de compilação base — na raiz do repositório do nosso caso, precisamos copiar nosso diretório "secreto" (aquele com iris.key, pwd.txt e load_ci_icm.script) no repositório clonado. Em seguida, o primeiro acesso ao terminal requer um usuário/senha, então nós os adicionamos a load_ci.script (por isso a linha vazia no início de load_ci.script). Por fim, criamos a imagem do docker e a marcamos adequadamente:  eduard93/icmdemo:$CI_COMMIT_REF_NAME onde $CI_COMMIT_REF_NAME é o nome de um branch atual. Observe que a primeira parte da tag de imagem deve ter o mesmo nome do nome do projeto no GitLab, para que possa ser vista na guia GitLab Registry (instruções sobre a marcação estão disponíveis na guia Registry). Dockerfile A criação de uma imagem docker é feita usando o [Dockerfile](https://docs.docker.com/engine/reference/builder/): FROM intersystems/iris:2018.1.1-released ENV SRC_DIR=/tmp/src ENV CI_DIR=$SRC_DIR/ci ENV CI_PROJECT_DIR=$SRC_DIR COPY ./ $SRC_DIR RUN cp $CI_DIR/iris.key $ISC_PACKAGE_INSTALLDIR/mgr/ \ && cp $CI_DIR/GitLab.xml $ISC_PACKAGE_INSTALLDIR/mgr/ \ && $ISC_PACKAGE_INSTALLDIR/dev/Cloud/ICM/changePassword.sh $CI_DIR/pwd.txt \ && iris start $ISC_PACKAGE_INSTANCENAME \ && irissession $ISC_PACKAGE_INSTANCENAME -U%SYS < $CI_DIR/load_ci.script \ && iris stop $ISC_PACKAGE_INSTANCENAME quietly Começamos a partir do contêiner básico iris. Primeiro, copiamos nosso repositório (e diretório "secreto") dentro do contêiner. Em seguida, copiamos a chave de licença para o diretório mgr. Em seguida, alteramos a senha para o valor de pwd.txt. Observe que pwd.txt é excluído nessa operação. Depois disso, a instância é iniciada e load_ci.script é executado. Por fim, a instância iris é interrompida. Estou usando o [executor GitLab Shell](https://docs.gitlab.com/runner/executors/), e não o executor Docker. O executor Docker é usado quando você precisa de algo de dentro da imagem, por exemplo, você está criando um aplicativo Android em um contêiner java e precisa apenas de um apk. No nosso caso, precisamos de um contêiner inteiro e, para isso, precisamos do executor Shell. Então, estamos executando comandos do Docker pelo executor GitLab Shell. ## Publicar Agora, vamos publicar nossa imagem em um Docker Hub publish image: stage: publish tags: - master script: - docker login -u eduard93 -p ${DOCKERPASSWORD} - docker push eduard93/icmdemo:$CI_COMMIT_REF_NAME Observe a variável ${DOCKERPASSWORD}, é uma [variável secreta](https://docs.gitlab.com/ee/ci/variables/#protected-variables) do GitLab. Podemos adicioná-la em GitLab > Project > Settings > CI/CD > Variables: ![](/sites/default/files/inline/images/vars.png) Os logs de job também não contêm valor de senha: Running with gitlab-runner 10.6.0 (a3543a27) on icm 82634fd1 Using Shell executor... Running on docker... Fetching changes... Removing ci/ HEAD is now at 8e24591 Add deploy to LIVE Checking out 8e245910 as master... Skipping Git submodules setup $ docker login -u eduard93 -p ${DOCKERPASSWORD} WARNING! Using --password via the CLI is insecure. Use --password-stdin. Login Succeeded $ docker push eduard93/icmdemo:$CI_COMMIT_REF_NAME The push refers to repository [docker.io/eduard93/icmdemo] master: digest: sha256:d1612811c11154e77c84f0c08a564a3edeb7ddbbd9b7acb80754fda97f95d101 size: 2620 Job succeeded e no Docker Hub podemos ver nossa nova imagem: ![](/sites/default/files/inline/images/d.png)   Executar Temos nossa imagem, agora vamos executá-la em nosso servidor de teste. Aqui está o script. run image: stage: run environment: name: $CI_COMMIT_REF_NAME tags: - master script: - docker exec icm sh -c "cd /icmdata/test && icm upgrade -image eduard93/icmdemo:$CI_COMMIT_REF_NAME" Com o ICM, precisamos executar apenas um comando ([icm upgrade](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GICM_using#GICM_using_deploy_manage_icmupgrade)) para fazer upgrade da implantação existente. Estamos chamando-a executando "docker exec icm sh -c ", que executa um comando especificado dentro do contêiner icm.  Primeiro, entramos no modo /icmdata/test, onde a definição da implantação do ICM é configurada para um servidor TEST. Depois disso, chamamos icm upgrade para substituir o contêiner existente por um novo contêiner. ## Teste Vamos fazer alguns testes. test image: stage: test tags: - master script: - docker exec icm sh -c "cd /icmdata/test && icm session -namespace USER -command 'do \$classmethod(\"%UnitTest.Manager\",\"RunTest\",\"MyApp/Tests\",\"/nodelete\")' | tee /dev/stderr | grep 'All PASSED' && exit 0 || exit 1" Novamente, estamos executando um comando dentro do nosso contêiner icm. A sessão icm executa um comando em um nó implantado. O comando executa testes de unidade. Depois disso, ele canaliza todos os resultados para a tela e também para o grep para encontrar os resultados dos testes de unidade e sair do processo com sucesso ou com um erro. ## Implantar A implantação em um servidor de produção é absolutamente igual à implantação em teste, exceto por outro diretório para a definição da implantação LIVE. Se os testes falhassem, essa etapa não seria executada. deploy image: stage: deploy environment: name: $CI_COMMIT_REF_NAME tags: - master script: - docker exec icm sh -c "cd /icmdata/live && icm upgrade -image eduard93/icmdemo:$CI_COMMIT_REF_NAME" Conclusão O ICM oferece uma maneira simples e intuitiva de provisionar uma infraestrutura na nuvem e implantar serviços nela, ajudando você a entrar na nuvem<nobr>agora</nobr> sem grande desenvolvimento ou reorganização. Os benefícios da infraestrutura como código (IaC) e da implantação em contêiner facilitam a implantação de aplicativos baseados no InterSystems IRIS em plataformas de nuvem públicas, como Google, Amazon e Azure, ou na sua nuvem privada VMware vSphere. Defina o que você quer, emita alguns comandos e o ICM faz o resto. Mesmo se você já estiver usando infraestrutura de nuvem, contêineres ou ambos, o ICM reduz drasticamente o tempo e o esforço necessários para provisionar e implantar seu aplicativo automatizando várias etapas manuais. Links * [Código do artigo](https://github.com/intersystems-ru/GitLab/tree/master/icm) * [Projeto de teste](http://gitlab.eduard.win/test/docker) * [Documentação do ICM](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GICM) * [First Look: ICM](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GICM_using)
Artigo
Danusa Calixto · Fev. 23, 2023

Entrega contínua de sua solução InterSystems usando GitLab – Parte VII: CD usando contêineres

Nesta série de artigos, quero apresentar e discutir várias abordagens possíveis para o desenvolvimento de software com tecnologias da InterSystems e do GitLab. Vou cobrir tópicos como: * Git básico * Fluxo Git (processo de desenvolvimento) * Instalação do GitLab * Fluxo de trabalho do GitLab * Entrega contínua * Instalação e configuração do GitLab * CI/CD do GitLab * Por que contêineres? * Infraestrutura dos contêineres * **CD usando contêineres** No [primeiro artigo](https://pt.community.intersystems.com/post/entrega-contínua-de-sua-solução-intersystems-usando-gitlab-–-parte-i-git), abordamos os fundamentos do Git, por que um entendimento de alto nível dos conceitos do Git é importante para o desenvolvimento de software moderno e como o Git pode ser usado para desenvolver software. No [segundo artigo](https://pt.community.intersystems.com/post/entrega-contínua-de-sua-solução-intersystems-usando-gitlab-–-parte-ii-fluxo-de-trabalho-do), abordamos o fluxo de trabalho do GitLab: um processo inteiro do ciclo de vida do software e a entrega contínua. No [terceiro artigo](https://pt.community.intersystems.com/post/entrega-contínua-de-sua-solução-intersystems-usando-gitlab-–-parte-iii-instalação-e), abordamos a instalação e configuração do GitLab e a conexão dos seus ambientes a ele No [quarto artigo](https://pt.community.intersystems.com/post/entrega-contínua-de-sua-solução-intersystems-usando-gitlab-–-parte-iv-configuração-da-cd), escrevemos uma configuração de CD. No [quinto artigo](https://pt.community.intersystems.com/post/entrega-contínua-de-sua-solução-intersystems-usando-gitlab-–-parte-v-por-que-contêineres), falamos sobre contêineres e como (e por que) eles podem ser usados. No [sexto artigo](https://pt.community.intersystems.com/post/entrega-contínua-de-sua-solução-intersystems-usando-gitlab-–-parte-vi-infraestrutura-dos), vamos discutir os principais componentes necessários para executar um pipeline de entrega contínua com contêineres e como eles trabalham juntos. Neste artigo, criaremos a configuração de entrega contínua discutida nos artigos anteriores. ## ## Fluxo de trabalho Na nossa configuração de entrega contínua: * Enviamos código para o repositório do GitLab * Criamos a imagem docker * Testamos * Publicamos a imagem no nosso registro docker * Trocamos o contêiner antigo pela nova versão do registro Ou em formato gráfico: Vamos começar. ## Criação Primeiro, precisamos criar nossa imagem. Nosso código seria, como sempre, armazenado no repositório, a configuração de CD em gitlab-ci.yml. No entanto, além disso (para aumentar a segurança), armazenaríamos vários arquivos específicos do servidor em um servidor de compilação. #### GitLab.xml Contém o código dos hooks de CD. Foi desenvolvido no [artigo anterior](https://pt.community.intersystems.com/post/entrega-contínua-de-sua-solução-intersystems-usando-gitlab-–-parte-iv-configuração-da-cd) e disponibilizado no [GitHub](https://github.com/intersystems-ru/GitLab/releases). É uma pequena biblioteca para carregar código, executar vários hooks e testar código. Como alternativa preferencial, você pode usar [submódulos git](https://git-scm.com/book/en/v2/Git-Tools-Submodules) para incluir este projeto ou algo semelhante no seu repositório. Os submódulos são melhores porque é mais fácil mantê-los atualizados. Uma outra alternativa seria marcar as versões no GitLab e carregá-las com o comando [ADD](https://docs.docker.com/engine/reference/builder/#add). #### iris.key Chave de licença. Como alternativa, ela pode ser baixada durante a compilação do contêiner em vez de armazenada em um servidor. É bastante arriscado armazenar no repositório. #### pwd.txt Arquivo contendo a senha padrão. Novamente, é bastante arriscado armazená-lo no repositório. Além disso, se você estiver hospedando um ambiente de produção em um servidor separado, ele poderá ter uma senha padrão diferente. #### load_ci.script O script inicial: * Ativa a autenticação do SO * Carrega GitLab.xml * Inicializa as configurações do utilitário GitLab * Carrega o código set sc = ##Class(Security.System).Get("SYSTEM",.Properties) write:('sc) $System.Status.GetErrorText(sc) set AutheEnabled = Properties("AutheEnabled") set AutheEnabled = $zb(+AutheEnabled,16,7) set Properties("AutheEnabled") = AutheEnabled set sc = ##Class(Security.System).Modify("SYSTEM",.Properties) write:('sc) $System.Status.GetErrorText(sc) zn "USER" do ##class(%SYSTEM.OBJ).Load(##class(%File).ManagerDirectory() _ "GitLab.xml","cdk") do ##class(isc.git.Settings).setSetting("hooks", "MyApp/Hooks/") do ##class(isc.git.Settings).setSetting("tests", "MyApp/Tests/") do ##class(isc.git.GitLab).load() halt Observe que a primeira linha é deixada em branco de maneira intencional. Como algumas configurações podem ser específicas do servidor, elas não são armazenadas no repositório, mas separadamente. Se o hook inicial for sempre o mesmo, você pode simplesmente armazená-lo no repositório. #### gitlab-ci.yml Agora, para a configuração da entrega contínua: build image: stage: build tags: - test script: - cp -r /InterSystems/mount ci - cd ci - echo 'SuperUser' | cat - pwd.txt load_ci.script > temp.txt - mv temp.txt load_ci.script - cd .. - docker build --build-arg CI_PROJECT_DIR=$CI_PROJECT_DIR -t docker.domain.com/test/docker:$CI_COMMIT_REF_NAME . O que está acontecendo aqui? Primeiro, como o [docker build](https://docs.docker.com/engine/reference/commandline/build/) pode acessar apenas subdiretórios de um diretório de compilação base — na raiz do repositório do nosso caso, precisamos copiar nosso diretório "secreto" (aquele com GitLab.xml, iris.key, pwd.txt e load_ci.script) no repositório clonado. Em seguida, o primeiro acesso ao terminal requer um usuário/senha, então nós os adicionamos a load_ci.script (por isso a linha vazia no início de load_ci.script). Por fim, criamos a imagem do docker e a marcamos adequadamente: docker.domain.com/test/docker:$CI_COMMIT_REF_NAME onde $CI_COMMIT_REF_NAME é o nome de um branch atual. Observe que a primeira parte da tag de imagem deve ter o mesmo nome do nome do projeto no GitLab, para que possa ser vista na guia GitLab Registry (instruções sobre a marcação estão disponíveis na guia Registry). #### Dockerfile A criação da imagem docker é feita usando o [Dockerfile](https://docs.docker.com/engine/reference/builder/): FROM docker.intersystems.com/intersystems/iris:2018.1.1.611.0 ENV SRC_DIR=/tmp/src ENV CI_DIR=$SRC_DIR/ci ENV CI_PROJECT_DIR=$SRC_DIR COPY ./ $SRC_DIR RUN cp $CI_DIR/iris.key $ISC_PACKAGE_INSTALLDIR/mgr/ \ && cp $CI_DIR/GitLab.xml $ISC_PACKAGE_INSTALLDIR/mgr/ \ && $ISC_PACKAGE_INSTALLDIR/dev/Cloud/ICM/changePassword.sh $CI_DIR/pwd.txt \ && iris start $ISC_PACKAGE_INSTANCENAME \ && irissession $ISC_PACKAGE_INSTANCENAME -U%SYS < $CI_DIR/load_ci.script \ && iris stop $ISC_PACKAGE_INSTANCENAME quietly Começamos a partir do contêiner básico iris. Primeiro, copiamos nosso repositório (e diretório "secreto") dentro do contêiner. Em seguida, copiamos a chave de licença e GitLab.xml para o diretório mgr. Em seguida, alteramos a senha para o valor de pwd.txt. Observe que pwd.txt é excluído nessa operação. Depois disso, a instância é iniciada e load_ci.script é executado. Por fim, a instância iris é interrompida. Veja o registro do job (parcial, os registros de carregamento/compilação foram ignorados): Running with gitlab-runner 10.6.0 (a3543a27) on docker 7b21e0c4 Using Shell executor... Running on docker... Fetching changes... Removing ci/ Removing temp.txt HEAD is now at 5ef9904 Build load_ci.script From http://gitlab.eduard.win/test/docker 5ef9904..9753a8d master -> origin/master Checking out 9753a8db as master... Skipping Git submodules setup $ cp -r /InterSystems/mount ci $ cd ci $ echo 'SuperUser' | cat - pwd.txt load_ci.script > temp.txt $ mv temp.txt load_ci.script $ cd .. $ docker build --build-arg CI_PROJECT_DIR=$CI_PROJECT_DIR -t docker.eduard.win/test/docker:$CI_COMMIT_REF_NAME . Sending build context to Docker daemon 401.4kB Step 1/6 : FROM docker.intersystems.com/intersystems/iris:2018.1.1.611.0 ---> cd2e53e7f850 Step 2/6 : ENV SRC_DIR=/tmp/src ---> Using cache ---> 68ba1cb00aff Step 3/6 : ENV CI_DIR=$SRC_DIR/ci ---> Using cache ---> 6784c34a9ee6 Step 4/6 : ENV CI_PROJECT_DIR=$SRC_DIR ---> Using cache ---> 3757fa88a28a Step 5/6 : COPY ./ $SRC_DIR ---> 5515e13741b0 Step 6/6 : RUN cp $CI_DIR/iris.key $ISC_PACKAGE_INSTALLDIR/mgr/ && cp $CI_DIR/GitLab.xml $ISC_PACKAGE_INSTALLDIR/mgr/ && $ISC_PACKAGE_INSTALLDIR/dev/Cloud/ICM/changePassword.sh $CI_DIR/pwd.txt && iris start $ISC_PACKAGE_INSTANCENAME && irissession $ISC_PACKAGE_INSTANCENAME -U%SYS < $CI_DIR/load_ci.script && iris stop $ISC_PACKAGE_INSTANCENAME quietly ---> Running in 86526183cf7c . Waited 1 seconds for InterSystems IRIS to start This copy of InterSystems IRIS has been licensed for use exclusively by: ISC Internal Container Sharding Copyright (c) 1986-2018 by InterSystems Corporation Any other use is a violation of your license agreement %SYS> 1 %SYS> Using 'iris.cpf' configuration file This copy of InterSystems IRIS has been licensed for use exclusively by: ISC Internal Container Sharding Copyright (c) 1986-2018 by InterSystems Corporation Any other use is a violation of your license agreement 1 alert(s) during startup. See messages.log for details. Starting IRIS Node: 39702b122ab6, Instance: IRIS Username: Password: Load started on 04/06/2018 17:38:21 Loading file /usr/irissys/mgr/GitLab.xml as xml Load finished successfully. USER> USER> [2018-04-06 17:38:22.017] Running init hooks: before [2018-04-06 17:38:22.017] Importing hooks dir /tmp/src/MyApp/Hooks/ [2018-04-06 17:38:22.374] Executing hook class: MyApp.Hooks.Global [2018-04-06 17:38:22.375] Executing hook class: MyApp.Hooks.Local [2018-04-06 17:38:22.375] Importing dir /tmp/src/ Loading file /tmp/src/MyApp/Tests/TestSuite.cls as udl Compilation started on 04/06/2018 17:38:22 with qualifiers 'c' Compilation finished successfully in 0.194s. Load finished successfully. [2018-04-06 17:38:22.876] Running init hooks: after [2018-04-06 17:38:22.878] Executing hook class: MyApp.Hooks.Local [2018-04-06 17:38:22.921] Executing hook class: MyApp.Hooks.Global Removing intermediate container 39702b122ab6 ---> dea6b2123165 [Warning] One or more build-args [CI_PROJECT_DIR] were not consumed Successfully built dea6b2123165 Successfully tagged docker.domain.com/test/docker:master Job succeeded Estou usando o [executor GitLab Shell](https://docs.gitlab.com/runner/executors/), e não o executor Docker. O executor Docker é usado quando você precisa de algo de dentro da imagem, por exemplo, você está criando um aplicativo Android em um contêiner java e precisa apenas de um apk. No nosso caso, precisamos de um contêiner inteiro e, para isso, precisamos do executor Shell. Então, estamos executando comandos do Docker pelo executor GitLab Shell. ###   ### Executar Temos nossa imagem, agora vamos executá-la.  No caso de ramificações de recursos, podemos simplesmente destruir o contêiner antigo e iniciar o novo. No caso do ambiente, podemos executar um container temporário e substituir o contêiner do ambiente caso os testes tenham êxito (isso fica como um exercício para o leitor). Aqui está o script. destroy old: stage: destroy tags: - test script: - docker stop iris-$CI_COMMIT_REF_NAME || true - docker rm -f iris-$CI_COMMIT_REF_NAME || true Esse script destrói o contêiner em execução no momento e é sempre bem-sucedido (por padrão, o docker falha se tentar parar/remover um contêiner inexistente). Em seguida, iniciamos a nova imagem e a registramos como um ambiente. [Contêiner Nginx ](https://cloud.google.com/community/tutorials/nginx-reverse-proxy-docker) faz proxy automático de solicitações usando a variável de ambiente VIRTUAL_HOST e a diretiva de exposição (para saber em qual porta fazer o proxy). run image: stage: run environment: name: $CI_COMMIT_REF_NAME url: http://$CI_COMMIT_REF_SLUG. docker.domain.com/index.html tags: - test script: - docker run -d --expose 52773 --env VIRTUAL_HOST=$CI_COMMIT_REF_SLUG.docker.eduard.win --name iris-$CI_COMMIT_REF_NAME docker.domain.com/test/docker:$CI_COMMIT_REF_NAME --log $ISC_PACKAGE_INSTALLDIR/mgr/messages.log ###   ### Testes Vamos fazer alguns testes. test image: stage: test tags: - test script: - docker exec iris-$CI_COMMIT_REF_NAME irissession iris -U USER "##class(isc.git.GitLab).test()" ### Publicar Por fim, vamos publicar nossa imagem no registro publish image: stage: publish tags: - test script: - docker login docker.domain.com -u dev -p 123 - docker push docker.domain.com/test/docker:$CI_COMMIT_REF_NAME O usuário/código pode ser transmitido usando [variáveis secretas do GitLab](https://docs.gitlab.com/ee/ci/variables/#secret-variables). Agora, podemos ver a imagem no GitLab: ![](/sites/default/files/inline/images/snimok_37.png) E outros desenvolvedores podem a extrair do registro. Na guia de ambientes, todos os ambientes estão disponíveis para a fácil navegação: ![](/sites/default/files/inline/images/snimok_39.png)   Conclusão Nessa série de artigos, discuti abordagens gerais de entrega contínua. É um tema extremamente vasto e essa série de artigos precisa ser vista mais como uma coleção de receitas do que algo definitivo. Se você deseja automatizar o desenvolvimento, os testes e a entrega do seu aplicativo, a entrega contínua em geral e o GitLab em particular é o melhor caminho. A entrega contínua e os contêineres permitem que você personalize seu fluxo de trabalho conforme necessário. ## Links * [Código do artigo](https://github.com/intersystems-ru/GitLab/tree/master/docker) * [Projeto de teste](http://gitlab.eduard.win/test/docker) * [Configuração de CD completa](https://github.com/intersystems-ru/GitLab/blob/master/docker/.gitlab-ci.yml) ## O que vem a seguir É isso. Espero que eu tenha abordado os conceitos básicos da entrega contínua e dos contêineres. Há vários tópicos sobre os quais não falei (talvez mais tarde), especialmente em relação a contêineres: * Os dados podem ser persistentes fora do contêiner. Veja a [documentação](http://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GICM_containers) relacionada. * Plataformas de orquestração como [kubernetes](https://kubernetes.io/) * [InterSystems Cloud Manager](http://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GICM_using) * Gerenciamento de ambiente - criando ambientes temporários para testes, removendo ambientes antigos após a mesclagem de ramificações de recursos * [Docker compose](https://docs.docker.com/compose/compose-file/) para implantações de vários contêineres * Diminuindo o tamanho da imagem docker e os tempos de construção * ...
Anúncio
Angelo Bruno Braga · Nov. 29, 2022

Hora de votar no Concurso InterSystems IRIS for Health: FHIR para a Saúde da Mulher

Olá Comunidade, É hora de votar! Vote nos melhores aplicativos em nosso concurso de programação IRIS for Health, focado na criação de soluções FHIR para a saúde da mulher: 🔥 VOTE NOS MELHORES APPS 🔥 Como votar? Detalhes abaixo. Nominação de Especialistas: O júri experiente da InterSystems escolherá os melhores aplicativos para indicar os prêmios na Nomeação de Especialistas. Dê as boas-vindas aos nossos especialistas: ⭐️ @Alexander.Koblov, Especialista de Suporte⭐️ @Alexander.Woodhead, Especialista Técnico⭐️ @Guillaume.Rongier7183, Engenheiro de Vendas⭐️ @Alberto.Fuentes, Engenheiro de Vendas⭐️ @Dmitry.Zasypkin, Engenheiro de Vendas Sênior⭐️ @Daniel.Kutac, Engenheiro de Vendas Sênior⭐️ @Eduard.Lebedyuk, Senior Cloud Engineer⭐️ @Steve.Pisani, Arquiteto de Soluções Sênior⭐️ @Patrick.Jamieson3621, Gerente de Produto⭐️ @Nicholai.Mitchko, Gerente, Engenharia de Vendas de Parceiros de Soluções⭐️ @Timothy.Leavitt, Gerente de Desenvolvimento⭐️ @Benjamin.DeBoe, Gerente de Produto⭐️ @Robert.Kuszewski, Gerente de Produto⭐️ @Stefan.Wittmann, Gerente de Produto⭐️ @Raj.Singh5479, Gerente de Produto⭐️ @Jeffrey.Fried, Diretor de Gestão de Produtos⭐️ @Aya.Heshmat, Especialista de Produto⭐️ @Evgeny.Shvarov, Gestor do Ecossistema de Desenvolvedores⭐️ @Dean.Andrews2971, Chefe de Relações com Desenvolvedores Nominação da Comunidade: Para cada usuário, uma pontuação mais alta é selecionada nas duas categorias abaixo: Condições Posição 1º 2º 3º Se você tiver um artigo publicado no DC e um aplicativo carregado no Open Exchange (OEX) 9 6 3 Se você tiver um artigo publicado no DC ou um aplicativo carregado no Open Exchange (OEX) 6 4 2 Se você fizer qualquer contribuição válida para a DC (postar um comentário/pergunta, etc.) 3 2 1 Nível Posição 1º 2º 3º Nível VIP no Global Masters ou Gerentes de Produto ISC 15 10 5 Nível Ambassador no GM 12 8 4 Nível Expert no GM ou Moderadores da Comunidade 9 6 3 Nível Specialist no GM 6 4 2 Nível Advocate no GM ou funcionários ISC 3 2 1 Voto cego O número de votos para cada aplicativo será ocultado de todos. Uma vez por dia, publicaremos a tabela de classificação nos comentários desta postagem. A ordem dos projetos na página do concurso será a seguinte: quanto mais cedo uma inscrição for enviada para o concurso, mais alta ela estará na lista. PS Não se esqueça de se inscrever nesta postagem (clique no ícone do sino) para ser notificado sobre novos comentários Para participar da votação, você precisa Entrar no Open Exchange – as credenciais da Comunidade funcionam. Faça qualquer contribuição válida para a comunidade de desenvolvedores – responda ou faça perguntas, escreva um artigo, contribua com aplicativos no Open Exchange – e você poderá votar. Verifique esta postagem sobre as opções para fazer contribuições úteis para a Comunidade de Desenvolvedores. Se mudou de ideia, cancele a escolha e dê seu voto para outro aplicativo! Apoie o aplicativo que você gosta! Observação: os participantes do concurso podem corrigir os bugs e fazer melhorias em seus aplicativos durante a semana de votação, portanto, não perca e assine para acompanhar os lançamentos de aplicativos!
Anúncio
Danusa Calixto · Dez. 22, 2022

Kits InterSystems IRIS : Instalação sem Apache web server (conhecido como Web Server Privado (PWS))

Se quiser experimentar o novo processo de instalação do projeto NoPWS, você pode obter acesso ao Early Access Program (EAP) aqui. (https://evaluation.intersystems.com/Eval/) Depois de se registrar, envie à InterSystems o endereço de e-mail que você usou para se registrar no EAP para nopws@intersystems.com. Veja aqui: Post Original