検索

Article
· Mai 16, 2024 9m de lecture

インターシステムズ製品をバックアップする前に確認したいこと

開発者の皆さん、こんにちは。

この記事では、InterSystems製品のバックアップ方法(4種類)のご紹介と、バックアップを行う前に確認しておきたい内容について解説します。

また、この記事に続くシリーズ記事では、それぞれのバックアップの仕組みと操作例を交えたバックアップとリストア手順を解説していきます。

シリーズ記事の中で行っているバックアップ練習、リストア練習の内容については、インターシステムズの講師付きトレーニングコースの中でも取り入れている内容で、一人1環境の演習環境内で実際にお試しいただいています。

参加者の皆さんと一緒に演習を進めて行きますと、データベースリストアの後に行うジャーナルリストアについては、ユーティリティから出力される確認項目が多いため、皆さん慎重に確認されながらリストアの指示を入力されています。そのため、リストア開始前の手続きや準備に意外と時間がかかっています。(実行例

普段なかなかバックアップやリストアを行う機会がないかと思いますが、万が一の場合に備え練習いただくことで実際のリストア作業が発生した際も落ち着いて対処できるようになるかと思います。

また、試さなくてもどんな感じになるのかをお読みいただくことで手続きの大枠がつかめ、心の準備ができるかと思います。まだ体験されたことない方はぜひご興味あるバックアップ手法に対するバックアップ・リストア方法をご確認下さい!


最初は、バックアップの種類について簡単にご紹介します。

 

InterSystems製品のバックアップ方法(4種類)

以下の4種類の方法を選択できます。

推奨方法) 外部バックアップは主に、論理ディスク・ボリュームの有効な ”スナップショット” を迅速に作成するテクノロジと共に使用します。 ここでは、バックアップ時、データベースへの書き込みをフリーズさせてからスナップショットを実行します。

この ”スナップショット” のようなテクノロジは、ストレージアレイからオペレーティング・システム、ディスクの単純なミラーリングに至るまで、さまざまなレベルで存在します。

InterSystems製品が用意するバックアップ機能を利用する方法で、バックアップ対象に設定した全データベースの使用済ブロックをバックアップする方法です。

管理ポータルメニューやタスクスケジュールにも含まれるメニューでお手軽ですが、データベースの使用済ブロック数が多くなればなるほどバックアップ時間も長くなりバックアップファイルサイズも大きくなってしまう方法です。

バージョン2024.1以降では、実験的機能としてオンラインバックアップの高速化機能を提供しています。

データベースファイル(DATファイル)の退避(ファイルコピーのような対退避方法も含)とオンライン・バックアップを組み合わせて利用する方法で、外部バックアップで使用するスナップショットのようなテクノロジが利用できない環境に対して素早くバックアップを取得できる方法です。(オンラインバックアップより高速にバックアップを実行できますが、手順は複雑です。)

InterSystems製品を停止できる場合に利用できる方法で手順がシンプルです。

 

シリーズ記事では、それぞれのバックアップ方法とリストア方法を解説していきますがその前に、 バックアップを取得する前に必ず確認しておきたい事 があります。

さて、それは何でしょうか・・・・・

 

👇

👇

それは、バックアップを取るデータベースの物理的な整合性が保たれているかどうかをバックアップ前に確認すること です。

万が一に備えてバックアップをとっていたとしても、バックアップ対象データベースの物理的な整合性が崩れている状態のバックアップはリストア対象として利用できません。

物理的な整合性=ディスク上のデータベース・ブロックの整合性

整合性が崩れた状態で取得したバックアップでは、正常な状態のデータベースに復旧させることができないためデータ喪失につながり、バックアップの目的が果たせず、非常に危険です。

バックアップが正常に成功していることを確認することも重要ですが、最も重要なことは データベースの整合性が保たれているデータベースをバックアップしているか ということです。

種類別のバックアップ方法、リストア方法紹介の前に、まずはデータベースの整合性チェックについて確認していきましょう。

 

データベースの物理的な整合性チェックツール

整合性チェックは、管理ポータルメニュー([システムオペレーション] > [データベース] > [整合性チェック]ボタン)や ^Integrity 、タスクスケジュールを使用して実行することができます。

管理ポータルメニューは以下の通りです。

システムルーチン:^Integrity を使用する場合は、IRISにログインし%SYSネームスペースに移動します。

チェックしたいデータベースを指定した実行もできますが、まずはシステム全体のチェックを実行してみます。

カレントデバイスに出力することもできますが、整合性チェックのログは長くなるので、例ではファイル出力先をフルパスで指定しています。

USER>set $namespace="%SYS"
%SYS>do ^Integrity
This utility is used to check the integrity of a database
and the pointer structure of one or more globals.

Output results on
Device: /usr/irissys/mgr/integ0424.log
Parameters? "WNS" =>
Stop after any error?  No=>
Do you want to check all databases?  No=> yes

ログ例は以下の通りです。

整合性チェックは全てのデータベースブロックについての検査結果を出力する長いログのため、一部省略+コメントを追記しています。

Intersystems IRIS Database Integrity Check on 04/08/2024 at 15:23:20
System: 733fea287670  Configuration: IRIS
IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2024.1 (Build 263U) Wed Mar 13 2024 15:21:28 EDT


《コメント》データベースディレクトリ毎に中身に含まれるデータベースブロックのつながりを検査します。

---Directory /usr/irissys/mgr/---

Global: %
 トップ/ボトムポインタレベル: ブロック数=1      8kb (充填率 0%)
 データレベル:           ブロック数=2      16kb (充填率 79%)
 合計:                ブロック数=3      24kb (充填率 53%)
 経過時間 = 0.204/08/2024 15:23:26
Global: %IRIS.SASchema
 トップ/ボトムポインタレベル: ブロック数=1      8kb (充填率 0%)
 データレベル:           ブロック数=1      8kb (充填率 11%)
 合計:                ブロック数=2      16kb (充填率 5%)
 経過時間 = 0.204/08/2024 15:23:26
<省略>

Global: rOBJ
 トップ/ボトムポインタレベル: ブロック数=1      8kb (充填率 37%)
 データレベル:           ブロック数=205      1,640kb (充填率 73%)
 ビッグストリング:          ブロック数=1,374      10MB (充填率 81%) カウント = 539
 合計:                ブロック数=1,580      12MB (充填率 80%)
 経過時間 = 0.204/08/2024 15:23:40
---Total for directory /usr/irissys/mgr/---
        95 Pointer Level blocks         760kb (16% full)
     6,634 Data Level blocks             51MB (83% full)
     1,574 Big String blocks             12MB (79% full) # = 696
     8,318 Total blocks                  64MB (81% full)
     1,279 Free blocks                10232kb

Elapsed time = 14.3 seconds 04/08/2024 15:23:40
《コメント》データベースディレクトリに対してチェックが終わると上記サマリを出力し、エラーがない場合は以下出力します。

No Errors were found in this directory.


《コメント》次のデータベースに対する整合性チェックを開始します。

---Directory /usr/irissys/mgr/HSCUSTOM/---

Global: EnsDICOM.Dictionary
 トップ/ボトムポインタレベル: ブロック数=1      8kb (充填率 0%)
 データレベル:           ブロック数=1      8kb (充填率 0%)
 合計:                ブロック数=2      16kb (充填率 0%)
 経過時間 = 0.204/08/2024 15:23:40
<省略>

Global: rOBJ
 トップ/ボトムポインタレベル: ブロック数=1      8kb (充填率 2%)
 データレベル:           ブロック数=19      152kb (充填率 76%)
 ビッグストリング:          ブロック数=259      2,072kb (充填率 60%) カウント = 259
 合計:                ブロック数=279      2,232kb (充填率 61%)
 経過時間 = 0.104/08/2024 15:23:47
---Total for directory /usr/irissys/mgr/HSCUSTOM/---
        48 Pointer Level blocks         384kb (11% full)
     2,150 Data Level blocks             16MB (70% full)
       272 Big String blocks           2176kb (60% full) # = 272
     2,485 Total blocks                  19MB (67% full)
       203 Free blocks                 1624kb

Elapsed time = 7.6 seconds 04/08/2024 15:23:47
No Errors were found in this directory.

《コメント》以降同様にデータベース毎にチェックを行い、エラーがある場合はその対象ブロックに対してエラー情報を出力します。エラーがない場合は各データベースのチェックの終わりに「No Errors were found in this directory.」と出力します。

すべてのデータベースの検査を終え、エラーがない事を確認すると以下1行出力し、整合性チェックが終了します。

No Errors were found.

 

タスクスケジュールについては、インストール時に毎週月曜日深夜2時に実行するタスクとして登録されていますが、一時停止状態で登録されています。

管理ポータル > [システムオペレーション] > [タスクマネージャ] > [タスクスケジュール] > Integrity Check 

整合性チェックは指定したデータベースの全データベースブロックを検査するため、チェック時間は、データ量、チェックするデータベース数、HWスペックに依存します。

目安となるような計測時間は特になく、実際稼働中の環境で実測した値を参考に予測していただく必要があります。

万が一の場合に備え、データベース整合性チェック時間のおおよその検討が付けられるように、実環境でテスト実行を行っていただくことを推奨します。

また、整合性チェック時間は環境により異なりますので、実稼働環境の状況に合わせ実行のタイミングをご検討ください。

もし、整合性チェックでエラーが出た場合は、すぐにサポートセンターまでご連絡ください。

 

以上、整合性チェックツールの使い方でした。

次は、いよいよバックアップ種類別のバックアップとリストア方法について解説します。

​​​​​​

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer
Article
· Mai 9, 2024 9m de lecture

Microsoft 365 - Events and Tasks

 In our previous article, we explored how to send emails through Microsoft 365 using the Graph API. Since then, an anonymous client reached out to me about setting up some other methods of notifications through that API. He was particularly interested in Outlook’s tasks and calendar events. 

If you still have your client ID, client secret, and application ID from the last exercise, you may continue utilizing them. We will reuse the globals we stored from before with the GetToken method. Most of the setup in Microsoft Entra will not need to be repeated. The only exception would be that you will have to go back to your application permissions and add the correct permissions for each item. We will start with adding a Task that requires permission Tasks.ReadWrite.All. Add that permission and grant admin consent employing the same process we described in the previous article.

As always, our API request will be built from a %Net.HttpRequest object. In this case, we will have to make two additional requests besides the one to get the token. Since Tasks in Outlook currently use Microsoft ToDo, your tasks can be organized into lists now. To create a task we must know the ID of the list to which we should send it. We will utilize the default task list for that. To find out its ID we need to create a request to the ToDo lists API. It will be a simple HTTP get request with no entity body, so it will be very easy.

set listRequest = ##class(%Net.HttpRequest).%New()
set listRequest.Server = "graph.microsoft.com"
set listRequest.SSLConfiguration = "O365"
set listRequest.Https = 1
set listRequest.Location = "/v1.0/users/youremail@domain.com/todo/lists"
do listRequest.SetParam("$filter","displayName eq 'Tasks'")
set sc = ..GetToken(.token)
do listRequest.SetHeader("Authorization","Bearer "_token)
set sc = listRequest.Get()

Pay attention to the parameter we set. On HTTP get requests, the graph API supports some OData filtering. By adding it, we specify that we are looking for the task list with the display name “Tasks,” which should be the default task list for most users. Since my client is not very tech savvy - he says he only ever accepts cookies with milk - he hasn’t changed the name of his default task list.

Note that we are going to employ the same basic setup that we operated for the email API request. The server will be graph.microsoft.com. We will  utilize the O365 SSL configuration. We will also get the bearer token and add it to the header. Then we will send the response to a location that includes the target user’s email address. This time we will operate the request’s Get() method rather than Post(). It will return a JSON response that will look similar to the one below:

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('########-####-####-####-############')/todo/lists",
    "value": [
        {
            "@odata.etag": "#####################################",
            "displayName": "Tasks",
            "isOwner": true,
            "isShared": false,
            "wellknownListName": "defaultList",
            "id": "There will be a big long string here."
        }
    ]
}

Without the filter parameter, we would get all user’s task lists. They often have at least two lists: a default task list and a separate one for flagged emails. If they set up other lists in ToDo, there will be even more. We are only interested in the default task list today. To get its ID, we should do the following:

set respObj = ##class(%Library.DynamicObject).%FromJSON(listRequest.HttpResponse.Data)
set respArray = respObj.%Get("value")
set listObj = respArray.%Get(0)
set ListID = listObj.%Get("id")

We need to use it in the task location to complete the request, so let's set it up similarly to the previous request.

set taskRequest = ##class(%Net.HttpRequest).%New()
set taskRequest.SSLConfiguration = "O365"
set taskRequest.Https = 1
set taskRequest.Server = "graph.microsoft.com"
set taskRequest.ContentType = "application/json"
set taskRequest.Location = "/v1.0/users/youremail@domain.com/todo/lists/"_ListID_"/tasks"

The body of this request will have a JSON structure. We could set just the title property of this JSON object and send the request. If we did it, it would give the user a new task with only that title and nothing else.

set mytask = ##class(%Library.DynamicObject).%New()
do mytask.%Set("title","Merry Christmas!")

However, my client’s needs are more advanced than that! He has a recurring annual task that requires a bit more information, including a small description, a due date, a reminder, and some recurrence. We will start with the body which will contain a very basic reminder. He is getting old, you know. So, the body will be a JSON object itself. Just like the email body, it will have two properties. One of them will be contentType which can be either “text” or “html”, and the other will be content, which will consist of the actual content of the body. Let's stick to a simple text.

set body = ##class(%Library.DynamicObject).%New()
do body.%Set("content","Don't forget to deliver!")
do body.%Set("contentType","text")
do mytask.%Set("body",body)

Since my client is a very influential man in charge of some crucial work, we will also set the importance of this task.

do mytask.%Set("importance","high")

He has also requested to add a due date and a reminder on the task. Additionally, his dates should be easy enough to remember. The dueDateTime property of the task should also be a JSON object with both a timestamp and a time zone. The reminder will likewise be the same kind of object, so we should set the isReminderOn property to true.

set duedate = ##class(%Library.DynamicObject).%New()
do duedate.%Set("dateTime","2024-12-25T00:00:00")
do duedate.%Set("timeZone","Etc/GMT")
do mytask.%Set("dueDateTime",duedate)
set reminder = ##class(%Library.DynamicObject).%New()
do reminder.%Set("dateTime","2024-12-24T00:00:00")
do reminder.%Set("timeZone","Etc/GMT")
do mytask.%Set("reminderDateTime",reminder)
do mytask.%Set("isReminderOn","true","Boolean")

Next, we need to deal with the recurrence. The recurrence object typically contains two more objects: a pattern and a range. The pattern tells us when this task recurs, and the range suggests how long it recurs. My client’s task is annual and will continue without an end, so I guess he will be doing this forever! 

We will start with the pattern. The type of pattern can be daily, weekly, relativeMonthly, absolutelyMonthly, relativeYearly, or absoluteYearly. For the monthly and yearly options, the absolute indicates that the event will occur on the exact same date, for example, September third of every year or on the tenth of every month. Relative means a certain occurrence of a day, like the third Thursday of every month or the fourth Thursday of every November. In my client’s case, it is an absolute yearly recurrence. The interval is based on the type. If it is a yearly event, 1 means this event will repeat every year. If it were a weekly event, an interval of 1 would mean one week. We should also set the month and dayOfMonth. For other types of recurrence, you may need to set the daysOfWeek property as well. It is a collection that can contain any day of the week. However, it does not apply in our case.

set pattern = ##class(%Library.DynamicObject).%New()
do pattern.%Set("type","absoluteYearly")
do pattern.%Set("interval",1)
do pattern.%Set("month",12)
do pattern.%Set("dayOfMonth",25)

The range can have one of three types: noEnd, endDate, and numbered. Since we are going to use the noEnd type, we only need to specify a start date and the type. If we were using the endDate type, we would have to specify an endDate, and if we were employing the numbered type, we would need to specify numberOfOccurrences as a positive integer telling us how many times the event will repeat.

set range = ##class(%Library.DynamicObject).%New()
do range.%Set("type","noEnd")
do range.%Set("startDate","2024-12-25")

Then we need to add the following code to a recurrence object and later add that object to our task. 

set recurrence = ##class(%Library.DynamicObject).%New()
do recurrence.%Set("pattern",pattern)
do recurrence.%Set("range",range)
do mytask.%Set("recurrence",recurrence)

Now we are finally ready to send off our request!

do taskRequest.EntityBody.Write(mytask.%ToJSON())
do taskRequest.Post()

If we have done everything correctly, we should get an HTTP response with a Status Code of 201 telling us that the task was created. The user should be able to see it in Outlook as soon as their Outlook syncs again.

 

After my client’s big annual event, they usually have a company party. He would like me to create an event on his Outlook calendar for it. To do it, you will need to go back to Entra and give your application the Graph API permission Calendars.ReadWrite. Simply sending an event request without specifying a calendar ID will add the event to the user’s default calendar. Once again, we will create a %Net.HttpRequest with our usual setup.

set evtRequest = ##class(%Net.HttpRequest).%New()
set evtRequest.Server = "graph.microsoft.com"
set evtRequest.SSLConfiguration = "O365"
set evtRequest.Https = 1
set evtRequest.Location = "/v1.0/users/"_..UserAddress_"/calendar/events"
set evtRequest.ContentType = "application/json"
set sc = ..GetToken(.token)
do evtRequest.SetHeader("Authorization","Bearer "_token)

Next, we have to set up the body of the request. This object will contain some properties that should look very familiar to you. The subject will be a simple string with a description of the event. The body will be the same kind of object as email and task bodies. There we must specify the content type as either "html" or "text". Additionally, remember to mention the start and end dates and times with the time zone included.

set evtObj = ##class(%DynamicObject).%New()
do evtObj.%Set("subject","After Party")
set bodyObj = ##class(%DynamicObject).%New()
do bodyObj.%Set("contentType","html")
do bodyObj.%Set("content","Party after the big day! <br /><b>BRING YOUR OWN NOG!</b>")
do evtObj.%Set("body",bodyObj)
set start = ##class(%Library.DynamicObject).%New()
do start.%Set("dateTime","2024-12-26T20:00:00")
do start.%Set("timeZone","Etc/GMT")
do evtObj.%Set("start",start)
set end = ##class(%Library.DynamicObject).%New()
do end.%Set("dateTime","2024-12-27T00:00:00")
do end.%Set("timeZone","Etc/GMT")
do evtObj.%Set("end",end)

There is a reminderMinutesBeforeStart field that will set a reminder for an event.

do evtObj.%Set("reminderMinutesBeforeStart",60)

We can also add a location, which is an object that can contain a name, address, coordinates, and some contact information.

set locObj = ##class(%Library.DynamicObject).%New()
do locObj.%Set("displayName","SeasonalSpirits")
set coordObj = ##class(%Library.DynamicObject).%New()
do coordObj.%Set("latitude",90)
do coordObj.%Set("longitude",0)
do locObj.%Set("coordinates",coordObj)
do evtObj.%Set("location",locObj)

It will not be much of a party if no one comes, so we should add some attendees too. It will be the same style of email address we used before, plus a type field specifying whether the attendee is required, optional, or a resource.
 

set attendees = ##class(%Library.DynamicArray).%New()
set myatt1 = ##class(%Library.DynamicObject).%New()
do myatt1.%Set("type","required")
set myemail1 = ##class(%Library.DynamicObject).%New()
do myemail1.%Set("name","Mr C.")
do myemail1.%Set("address","youremail@domain.com")
do myatt1.%Set("emailAddress",myemail1)
do attendees.%Push(myatt1)
set myatt2 = ##class(%Library.DynamicObject).%New()
do myatt2.%Set("type","optional")
set myemail2 = ##class(%Library.DynamicObject).%New()
do myemail2.%Set("name","Mrs. C.")
do myemail2.%Set("address","youremail2@domain.com")
do myatt2.%Set("emailAddress",myemail2)
do attendees.%Push(myatt2)
do evtObj.%Set("attendees",attendees)

Finally, we are ready to write the request body and post it.

do evtRequest.EntityBody.Write(evtObj.%ToJSON())
do evtRequest.Post()

Once again, if we have done all of the abovementioned correctly, we should get an HTTP response with a status code of 201, and the user should now have the event on their default calendar.

 

That is all for now! However, it seems to me that I have just got another email from my mysterious client. It is something related to managing big and busy teams of builders, stable managers, etc. This guy’s business is really weird! I have a feeling I will be back soon, talking about Teams.  

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer
Annonce
· Mai 7, 2024

Recapitulação do InterSystems Developer Community, Abril 2024

Olá e Bem-vindo à recapitulação da Comunidade de Desenvolvedores Abril 2024.
Estatísticas gerais
21 novas postages publicadas em Abril:
 12 novos artigos
 9 novos anúncios
2 novos membros ingressaram em Abril
1,049 postagens publicadas ao todo
575 membros ingressaram ao todo
Principais publicações
Principais autores do mês
Artigos
#InterSystems IRIS
 
#Caché
Depurando a Web
Por Danusa Calixto
 
#HealthShare
 
#Outro
 
Anúncios
#InterSystems IRIS
 
#Developer Community Oficial
 
#InterSystems IRIS for Health
 
#Global Masters
 
#InterSystems Oficial
 
#Portal de Aprendizagem
 
Abril, 2024Month at a GlanceInterSystems Developer Community
Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer
Annonce
· Mai 6, 2024

Tercer concurso de artículos técnicos en español

¡Hola Comunidad!

Llega un nuevo reto para vosotros ¡El tercer concurso de redacción de artículos técnicos de InterSystems en español ya está aquí!

🏆 3º Concurso de Artículos Técnicos en español 🏆
Descripción del concurso: Escribe un artículo en español en la Comunidad de Desarrolladores, sobre cualquier tema relacionado con la tecnología de InterSystems.

Duración: del 6 de mayo al 2 de junio de 2024.

Premios para todos los participantes: Todas las personas que publiquen un artículo en español durante la vigencia del concurso recibirán un premio.

Premio principal: LEGO Ferrari Daytona SP3 / Banco Mágico Gringotts™ - Edición para coleccionistas. 

 

¡Participa en el concurso y alcanza a cientos de usuarios! Es una de las mejores oportunidades para publicar esos consejos que has descubierto.

Premios

1. Todos los participantes ganan en el concurso de artículos técnicos de InterSystems -> Cualquier miembro de la Comunidad que participe en el concurso, recibirá un detalle de InterSystems por participar.

2. Premios de los Expertos – los artículos ganadores de esta categoría serán elegidos por expertos de InterSystems y podrán elegir en cada caso:

🥇 1er puesto: LEGO Ferrari Daytona SP3 o Banco Mágico Gringotts™ - Edición para coleccionistas. 

🥈 2do puesto: LEGO Sistema de Lanzamiento Espacial Artemis de la NASA o Chaqueta hombre Patagonia Nano Puff® Hoody.

🥉 3er puesto: Altavoz JBL Flip 6, Amazon Kindle 8G Paperwhite (Onceava generación) o Mochila Samsonite SPECTROLITE 3.0 15.6"

O como alternativa, cualquier ganador puede elegir un premio de una categoría inferior a la suya

Nota: Los premios están sujetos a cambiar si la disponibilidad en el país no permite su entrega.

3. Premio de la Comunidad de Desarrolladores – artículo con el mayor número de "Me gusta". La persona que gane, podrá elegir uno de estos premios:

🎁 Altavoz JBL Flip 6, Amazon Kindle 8G Paperwhite (Onceava generación) o Mochila Samsonite SPECTROLITE 3.0 15.6" 

Nota: cada autor solo puede ganar un premio de cada categoría (en total, un autor puede ganar dos premios: uno en la categoría Expertos y otro en la categoría de la Comunidad).

¿Quién puede participar?

Cualquier persona registrada en la Comunidad de Desarrolladores, excepto los empleados de InterSystems. Regístrate aquí en la Comunidad si aún no tienes una cuenta.

Duración del concurso

📝  Del 6 de mayo al 2 de junio: Publicación de artículos.

📝  Del 3 de junio al 9 de junio: Fase de votación. 

Publica tu(s) artículos(s) durante ese período. Los miembros de la Comunidad de Desarrolladores pueden ir votando los artículos que les gustan haciendo clic en "Me gusta" debajo de cada artículo.

Truco: Cuanto antes publiques tu(s) artículo(s), más tiempo tendrás para conseguir más votos de los Expertos y de la Comunidad.

🎉 10 de junio: Anuncio de los ganadores.

    Requisitos

    ❗️ Cualquier artículo escrito durante el período de duración del concurso y que cumpla los siguientes requisitos entrará automáticamente en la competición ❗️:

    • El artículo debe estar relacionado directa o indirectamente con la tecnología de InterSystems (características propias de los productos de InterSystems o, también, herramientas complementarias, soluciones arquitecturales, mejores prácticas de desarrollo,…).
    • El artículo debe estar escrito en español.
    • El artículo debe ser 100% nuevo (puede ser la continuación de un artículo ya publicado).
    • El artículo no puede ser una copia o traducción de otro publicado en la Comunidad de Desarrolladores en español o en otra Comunidad.
    • Tamaño del artículo: >1 000 caracteres (los enlaces no cuentan en el cálculo de caracteres).
    • Modo de participación: individual (se permite que un participante publique varios artículos).

    ¿Sobre qué se puede escribir?

    Se puede escoger cualquier tema técnico relacionado directa o indirectamente con la tecnología de InterSystems.

    🎯 BONUS:

    Los Expertos conceden 3 votos al artículo que consideran el mejor, 2 votos al 2º que consideran mejor y 1 voto al 3º que consideran mejor. Además, los artículos pueden recibir más puntos en función de los siguientes bonus:

    Nota: la decisión de los jueces es inapelable.

    1. Bonus por autor nuevo: Si es la primera vez que participas en el Concurso de Artículos Técnicos en Español, tu artículo recibirá un 1 voto extra de los Expertos.

    2. Bonus por temática: Si tu artículo está dentro de las siguientes temáticas, recibirá 2 puntos extra.

    • Uso de AI/ML/GenAI
    • Cómo aprovechar las posibilidades de la búsqueda vectorial (Vector Search)
    • Aprovechamiento de la función de almacenamiento en columnas
    • ️Uso de Python integrado
    • Uso de Cloud SQL
    • Uso de VSCode
    • Explotación de las capacidades FHIR de IRIS (SMART en FHIR 2.0, modelo de objetos FHIR, FHIR SQL Builder, Bulk FHIR,...)


    3. Vídeo bonus: si además del artículo, se acompaña con un vídeo explicativo, el candidato recibirá 4 puntos.

    4. Bonus por tutorial: Recibirás 3 puntos si el artículo tiene características de tutorial, con instrucciones paso a paso que un desarrollador pueda seguir para completar una o varias tareas específicas.


    Así que... Let's go!

    ¡Esperamos ansiosos vuestros artículos! 

    ¡Comunidad! ¡Que la fuerza os acompañe! ✨🤝

    3 Comments
    Discussion (3)1
    Connectez-vous ou inscrivez-vous pour continuer
    Article
    · Mai 3, 2024 6m de lecture

    Demo: Connecting Locally to an S3 Bucket without an AWS Account

    Introduction

    Accessing Amazon S3 (Simple Storage Service) buckets programmatically is a common requirement for many applications. However, setting up and managing AWS accounts is daunting and expensive, especially for small-scale projects or local development environments. In this article, we'll explore how to overcome this hurdle by using Localstack to simulate AWS services. Localstack mimics most AWS services, meaning one can develop and test applications without incurring any costs or relying on an internet connection, which can be incredibly useful for rapid development and debugging. We used ObjectScript with embedded Python to communicate with Intersystems IRIS and AWS simultaneously. Before beginning, ensure you have Python and Docker installed on your system. When Localstack is set up and running, the bucket can be created and used. 

    Creating an S3 Bucket from ObjectScript with Embedded Python

    Now that LocalStack is running, let's create an S3 bucket programmatically. We'll use Python and the Boto3 library - a Python SDK for AWS services. Take a look at the MakeBucket method provided in the S3UUtil class. This method utilizes Boto3 to create an S3 bucket:

    ClassMethod MakeBucket(inboundfromiris As %String) As %Status [ Language = python ]
    
    {
    
        import boto3
    
        s3 = boto3.client(
    
            service_name='s3', 
    
            region_name="us-east-1", 
    
            endpoint_url='http://host.docker.internal:4566', 
        )
    
        try:
    
            s3.create_bucket(Bucket=inboundfromiris)
    
            print("Bucket created successfully")
    
            return 1
        except Exception as e:
    
            print("Error:", e)
    
            return 0
    }

    To create a bucket, you would call this method with the desired bucket name:

    status = S3UUtil.MakeBucket("mybucket")

    Uploading Objects to the Bucket from ObjectScript with Embedded Python

    Once the bucket is created, you can upload objects to it programmatically. The PutObject method demonstrates how to achieve this:

    ClassMethod PutObject(inboundfromiris As %String, objectKey As %String) As %Status [ Language = python ]
    
    {
    
        import boto3
    
        try:
    
            content = "Hello, World!".encode('utf-8')
    
            s3 = boto3.client(
    
                service_name='s3',
    
                region_name="us-east-1",
    
                endpoint_url='http://host.docker.internal:4566'
            )
    
            s3.put_object(Bucket=inboundfromiris, Key=objectKey, Body=content)
    
            print("Object uploaded successfully!")
    
            return 1
        except Exception as e:
    
            print("Error:", e)
    
            return 0
    }

    Call this method to upload an object:

    Do ##class(S3.S3UUtil).PutObject("inboundfromiris", "hello-world-test")

     

    Listing Objects in the Bucket from ObjectScript with Embedded Python

    To list objects in the bucket, you can use the FetchBucket method:

    ClassMethod FetchBucket(inboundfromiris As %String) As %Status [ Language = python ]
    
    {
    
        import boto3
    
        s3 = boto3.client(
    
            service_name='s3', 
    
            region_name="us-east-1", 
    
            endpoint_url='http://host.docker.internal:4566', 
        )
    
        try:
    
            response = s3.list_objects(Bucket=inboundfromiris)
    
            if 'Contents' in response:
    
                print("Objects in bucket", inboundfromiris)
    
                for obj in response['Contents']:
    
                    print(obj['Key'])
    
                return 1
            else:
    
                print("Error: Bucket is empty or does not exist")
    
                return 0
        except Exception as e:
    
            print("Error:", e)
    
            return 0
    }

    Call the FetchBucket method to list objects from the bucket:

    do ##class(S3.S3UUtil).FetchBucket("inboundfromiris")


     

    Retrieving Objects from the Bucket from ObjectScript with Embedded Python

    Finally, to retrieve objects from the bucket, you can use the PullObjectFromBucket method:

    ClassMethod PullObjectFromBucket(inboundfromiris As %String, objectKey As %String) As %Status [ Language = python ]
    
    {
    
        import boto3
    
        def pull_object_from_bucket(bucket_name, object_key):
    
            try:
    
                s3 = boto3.client(
    
                    service_name='s3', 
    
                    region_name="us-east-1", 
    
                    endpoint_url='http://host.docker.internal:4566', 
                )
    
                obj_response = s3.get_object(Bucket=bucket_name, Key=object_key)
    
                content = obj_response['Body'].read().decode('utf-8')
    
                print("Content of object with key '", object_key, "':", content)
    
                return True
    
            except Exception as e:
    
                print("Error:", e)
    
                return False
    
        pull_object_from_bucket(inboundfromiris, objectKey)
    
    }

    Call this method:

    Do ##class(DQS.CloudUtils.S3.S3UUtil).PullObjectFromBucket("inboundfromiris", "hello-world-test")

     

    The discussion here is just the beginning, as it's clear there's plenty more ground to cover. I invite readers to dive deeper into this subject and share their insights. Let's keep the conversation going and continue advancing our understanding of this topic.

    I'm eager to hear thoughts and contributions.

    Discussion (0)1
    Connectez-vous ou inscrivez-vous pour continuer