Search

Clear filter
Article
Yuri Marx · Mar 1, 2021

Day 4: Developing with InterSystems Objects and SQL

I'm participating in the Developing with InterSystems Objects and SQL with Joel Solon. The course is very nice and I will share with you some tips I got during the training. Tips presented in the day 4: All data are stored in Globals and Global names start with ^. Example of global: ^animal. Global can have multiples locations to the data ("sub data"). Example: ^animal(1). ^%* globals are accessible from any system-wide (from any namespace). Globals enables IRIS to support multimodel data (object, relational, document, multidimensional, etc). To see globals go the Management Portal > Explorer > Globals > Select Global > View or in Terminal type do ^%G or zwrite ^global. There are an automatic correspondence between persistent classes and SQL Tables: Package is SQL Schema; Class is a Table; Property is a Column; Method is a Store Procedure; (when sqlProc); Relationship between classes is a SQL Foreign Key constraint (must be bi-directional); Object is a Row. One table can correspond to multiple classes, but serial class is part of the table of the persistent class (don't have a specific table). One class can correspond to multiple tables. We have some classes types: Non-registered: not class object (container for methods only); Registered: transient objects; Persistent: SQL persistence in tables; Serial: SQL persistence in the main table (serial is embedded); Datatype: not class object is used to do new validations and conversions to base data types. Classes can be composed by: Properties; Methods; Class queries: SQL Select statements; Parameters: user constants or system constants to configure the class behavior; Foreign keys: to referencial integrity; Indexes: to improve performance and do unique values; Triggers: fire methods associated with persistence events; XData: XML or JSON definitions associated with the class; Storage: description of the data storage. Classes by convention has first letter of the word in Capital. Example: CountryOrigin. Parameters are all capital. Example: COLORNUMBER. Class attributes qualify/configure a class. Example [SqlTableName = Animal] set the table name to a class. [Final] not allows inheritence. [Private] not allows call methods or use properties for non-subclasses. Internally IRIS generate Get and Set to properties, and are not visible but can be declared to change the behavior. Is possible override a method of the superclass, to do this, repeat the class name, the arguments. Is possible increase the number of arguments, not decrease. Use ##super() to call base class method. To create abstract class use [Abstract] and prevent instantiation. Is possible extends multiple classes. Example Class Person extends (%Persistent, %Animal). (Persistent must be the fisrt in the extends, see joel tip in the comments) REST is REpresentational State Transfer. Is based in the HTTP protocol. Use HTTP verbs: GET (select), POST (insert), PUT (update) and DELETE (delete). For expose your class as REST resource extend from %CSP.REST. Use URLMap inside XData block to configure the routes of your REST service. Using the Portal, create a Web Application, enable REST and specify Dispatch class. %JSONAdaptor provides convertion between objects and JSON. Use obj.%JSONImport(jsonObj) to assign DynamicObject to a object. Use obj.%JSONExportToString(.jsonString) to write a JSON String to a object. %JSON.Formatter format a JSON String for human readability. Good tips! Congrats! Could you give an example for items 6 and 7? I always thought that the relationship was a class for a table. 6 & 7 are side effects of object inheritance.Think of a class Person.But Employee Extends PersonSimilar Students Extends Person tooSo you have 3 tables but all are Persons Some with extension some not. @6: Table Employee corresponds to class Person and to class Employee @7: So class person corresponds to Table PERSON, EMPLOYEE , STUDENT Yes, thanks the nice example. Regarding 9, can we change the stored information manually? I know it is generated automatically. @9.9. storage is generated once if not existing yet.you may change it manually (typically data location global) as long as there is nothing stored yetotherwise you lose the existing content. Or you copy it to the new location.My article The adopted Bitmap shows such an example [actually also in contest} Hello YURI MARX GOMES, Thank you for your articles. Always good tips Thanks @Delphine.Morel, good to hear this, is an incentive to keep writing more articles. Point 5-5: Relationship on the object side is bi-directional. Class A has a reference to class B, and class B has a collection of references to class A. On the SQL side, table A has a reference to table B, along with automatic referential integrity. Point 16: Important: for a class to be persistent, %Persistent must be the first class. So the example should be: Class Person extends (%Persistent, Animal) Thanks additional tips! If there is no storage definition then a storage definition whose type is %Storage.Persistent is created when compiling the class. This is done before the storage definition is compiled (every class member is compiled by the class compiler). Then, when the storage definition is compiled and if the type is %Storage.Persistent then the %Storage.Persistent.STORAGECOMPILERCLASS will generate a full storage definition for the current class definition. What does that mean? Well - if this is the first time this storage definition has been compiled then it is most likely empty, other than the type class. The STORAGECOMPILERCLASS will generate a complete storage definition. But even if the storage definition is already defined, the STORAGECOMPILERCLASS still reviews that definition. If there are any changes detected to the class definition then the storage definition is updated to reflect those changes. That means that the user can manually edit the storage definition at any time and the storage compiler will simply make sure that the definition is "complete" - no missing properties, no missing indexes, and so on. Bottom line is that the user is free to make any desired changes, including deleting the storage definition completely. Keep in mind that some changes can make the compiled class incompatible with existing data. Just to clarify - inheritance considers the primary super class hierarchy. %Persistent must be the first class some where in the primary super class hierarchy. Sample.Employee extends Sample.Person which extends %Library.Persistent. Great, thanks!
Article
Yuri Marx · Mar 2, 2021

Day 5: Developing with InterSystems Objects and SQL

I finished my participation in the Developing with InterSystems Objects and SQL with Joel Solon. The course is very nice and I will share with you some tips I got during this the training final day. Tips presented in the day 5: %SYSTEM package has general utiliy classes. Use $system.class.Help() to list the utilities. The main %SYSTEM classes are Encryption (industry encryption methods), OBJ to manage classes and objects, Security for security methods and SQL to use SQL language. IRIS allows validation to the properties and arguments using MINVAL and MAXVAL to integer, FORMAT to date and time, SCALE to decimal, MINLEN, MAXLEN, TRUNCATE, VALUELIST (restrict the input to a list of values) and PATTERN to string. Example: Method Print(name As %String(MAXLEN=50)). You can create new data type validations and convertions extending a datatype like %String and using DisplayToLogical() and LogicalToDisplay() to implement new behaviors. Is possible change the datatype parameter like the PATTERN parameter for change the validation of a string. IRIS uses -> operator to do implicit joins, example: select Country->States->County from Simple.Places. This joins 3 related tables. To create a reference between classes/tables use ForeignKey. Example: ForeignKey CountryFK(Country) References Simple.Country() [ OnDelete = setnull ]. There are the options setnull to set null to the otherside table/class, cascade to propagate the deletion, noaction to no action and setdefault to configure a default value to the reference. Use %ConstructClone() to do a clone of a object and its references. Use SqlComputeCode to the calculated fields. Example: (from IRIS documentation) Property FullName As %String [ SqlComputeCode = {set {*}={FirstName}_" "_{LastName}}, SqlComputed ]; Is possible automate tests using %UnitTest framework. Use %UnitTest.TestCase for defining test cases and %UnitTest.Manager for running a set of Test Cases. To see the results go to System Explorer > Tools > UnitTest Portal. See https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=TUNT. IRIS supports 2 type collections: List: key based on position starting in 1. Declaration: Property States as list of Simple.State. Get: country.States.GetAt(1) Insert: country.States.Insert(florida) Remove: country.States.RemoveAt(1) Count: country.States.Count() Clear: country.States.Clear() Next: country.States.GetNext(1) - to get item 2 Loop: for i=1:1:country.States.Count() { write !, country.States.GetAt(i) Array: key based on associated value. Declaration: Property States as array of Simple.State. Get: country.States.GetAt("FL") Insert: country.States.SetAt(florida, "FL") Remove: country.States.RemoveAt("FL") Count: country.States.Count() Clear: country.States.Clear() Next: country.States.GetNext("FL") - to get item GA Loop: set state = "" for { set val = country.States.GetNext(.state) quit: (state = "") write !, val } To create relationships between classes, we have: Parent/Children: Relationship States as Simple.State [ cardinality = children, Inverse = Country ]. The otherside: Relationship Country as Simple.Country [ cardinality = parent, Inverse = Country ]. One/Many: Relationship States as Simple.State [ cardinality = many, Inverse = Country ]. The otherside: Relationship Country as Simple.Country [ cardinality = one, Inverse = Country ]. One-To-One and Many-to-Many are not supported. One-To-One may be simulated and Many-To-Many can be made using 2 Many-to-One to a relationship table. Stream is object that can contain amount of data larger than limit of regular properties, may store characters (%Stream.GlobalCharacter) or binary (%Stream.GlobalBinary) data. Use the following methods to read/write data: Write(text): write in the end of line; WriteLine(text): write to a new line; Clear(): clear the content of the stream; CopyFrom(stream): copy from a stream and overwrite the current content; Read(length): read characters limited to the length; ReadLine(length): read characters in the current line limited to the length; Rewind(): retorna para o início do stream; MoveToEnd(): move to end of stream. You can use triggers to do something before or after a CRUD event. Example: Trigger T1 [Event = INSERT, Time = AFTER, Order = 1, Foreach = row/object] { write your code }. The IRIS has some functions frequently used: $EXTRACT: get a substring - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fextract $FIND: get the position of a value passed as argument - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_ffind $LENGTH: get the size of a string or substring - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_flength $LIST: return/create a list of elements - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_flist $LISTDATA: return the element in the list by position - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_flistdata $LISTFIND: return the index of a element in the list - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_flistfind $LISTGET - get an element in the list - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_flistget $LISTLENGTH - get total of elements in the list - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_flistlength $PIECE - return or replace a substring using a delimiter - https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fpiece The course was very nice and has a rich set of practical exercices. The course is important to preparation to IRIS developer certification too. See the course agenda in https://www.intersystems.com/support-learning/learning-services/classroom-learning/?course-view=course-schedule. @11: 1:1 could be a degraded 1:N relationship orby inheriting from a base class as mentioned earlier: "Employee Extends Person" many-to-many can be covered as M:N relationship as I described in my article 3 years ago. Thanks Cemper. Point #11: one-to-one is not supported but can be imperfectly simulated. many-to-many is supported by combining one-to-many among 3 classes. Oops! I posted this without noticing that Robert already handled this one! Perfect! Thanks the contribution! The interactive tutorials with exercises built into the documentation helped me a lot in my time: Caché Tutorial Topics Map Caché Tutorials Also included was a database "SAMPLES" (code and data) with examples for every taste. I often used it for performance testing. Note: I give a link to version 2016.2, because since version 2017.1, for some reason, the developers have changed the display styles in the online documentation and removed some information. Local documentation does not have these disadvantages. In addition, in the <cachesys>\dev\ folder there were numerous demos with source code for various programming languages and connection technologies (С++, C#, Java, PHP, Python, ODBC, JDBC, ADO.NET, ActiveX, XEP, etc.): Incomplete content \dev\tutorials\ \dev\tutorials\csp \dev\tutorials\java \dev\tutorials\mv \dev\tutorials\pojo \dev\tutorials\security \dev\tutorials\UnitTestEx \dev\tutorials\webservices \dev\tutorials\zen \dev\Cache\ \dev\Cache\callin \dev\Cache\callout \dev\Cache\cctrlcpp \dev\Cache\cctrlvb \dev\Cache\ctrldemo \dev\Cache\HAcluster \dev\odbc\samples\ \dev\odbc\samples\php \dev\odbc\samples\select \dev\odbc\samples\sqlgateway \dev\python\ \dev\python\samples \dev\python\samples3 \dev\cdirect \dev\cpp\samples \dev\dblib\samples \dev\dotnet\samples \dev\java\samples \dev\mv\samples \dev\node.js\samples \dev\perl\samples Great tip, thanks! I think Objects and Groovy are actually a bit similar... I don't know if my idea is right or wrong, actually I write very little Objects. Thank you for sharing your experience, It seems to be an enriching training
Announcement
Evgeny Shvarov · Mar 3, 2021

Technology Bonuses for Projects of the InterSystems Grand Prix!

Hi Developers! We had a set of technology bonuses for the InterSystems Grand Prix contest. And here is how projects collected it: Project Total Bonus zapm 10 HealthInfoQueryLayer 13 Data extraction solution between heterogeneous systems 0 Airplane React, Material UI, and REST API 10 springboot-iris-crud 10 iris-rad-studio 4 iris-python-suite 7 fhir-chatbot 11 iris-ml-suite 10 IRIS Interoperability Message Viewer 10 isc-generate-db 10 iris-image-index-demo 17 iris4health-fhir-analytics 23 interoperability-integratedml-adapter 23 iris-integratedml-monitor-example 12 iris-analytics-notebook 14 ObjectScript Reports 0 iris-for-money 12 vscode-intersystems-iris 14 ObjectScript Kernel 5 apptools-admin 10 RESTFUL_API_For_Hotel_OverBooking_System 10 units 2 realworld-intersystems-iris 12 isc-tar 6 BlocksExplorer 8 iris-fhir-portal 15 npm-iris 12 iris-history-monitor 12 Dictionary comparison scheme of cache database 0 IRIS-REST-API-DATABASEMANAGER 13 ISC DEV 4 M-commands instead of Excel formulas in cells 2 appmsw-telestat 13 isc-apptools-lockdown 4 WebSocket Client JS with IRIS Native API as Docker Micro Server 5 Wsock-Embedded-Py 10 Terminal Multi-Line Command Editor 4 The adopted Bitmap 8 Using ZPM for Node.js 7 cmPurgeBackup 4 IRIS import manager 5 Questy 7 ➡️ Here you can find a detailed distribution of bonuses for each application ⬅️ This table is subject to change upon project improvements or if we missed something. Fill free to claim the bonus in the comments here or on discord. Stay tuned!
Announcement
Anastasia Dyubaylo · Jun 10, 2021

Video: Automating InterSystems IRIS Instances Configuration

Hi Community, Please welcome the new video on InterSystems Developers YouTube: ⏯ Automating InterSystems IRIS Instances Configuration Learn how the CPF merge facility allows you to define, in an easy and declarative way, the ultimate state of an InterSystems IRIS data platform instance. This solution allows you to embrace cloud-native, GitOps-like configuration operations. 🗣 Presenter: @Luca.Ravazzolo, InterSystems Product Manager Additional materials to this video you can find in this InterSystems Online Learning Course. Enjoy watching this video! 👍🏼
Announcement
Anastasia Dyubaylo · Jun 22, 2021

InterSystems AI Contest Kick-Off Webinar

Hi Community, We're pleased to invite all the developers to the upcoming InterSystems AI Contest Kick-Off Webinar! The topic of this webinar is dedicated to the InterSystems AI programming contest. During the webinar, we will demo how to load data into IRIS, how to deal with it using ODBC/JDBC and REST, and how to use special AI/ML features of IRIS: IntegratedML, DataRobot, R Gateway, Embedded Python, PMML. Date & Time: Monday, June 28 — 11:00 AM EDT Speakers: 🗣 @Aleksandar.Kovacevic, InterSystems Sales Engineer🗣 @Théophile.Thierry, InterSystems Intern🗣 @Robert.Kuszewski, Product Manager - Developer Experience, InterSystems 🗣 @Evgeny.Shvarov, InterSystems Developer Ecosystem Manager Join the webinar to find out all the details about this competition and ask your questions to our speakers! ✅ REGISTER TODAY! Hey Developers, The recording of this webinar is available on InterSystems Developers YouTube! Please welcome: ⏯ InterSystems AI Contest Kick-Off Webinar Big applause to our speakers! 👏🏼
Question
Muhammad Waseem · Jun 14, 2021

Visual studio .Net over InterSystems studio

Just want to know what is the reason to user Visual Studio .Net editor over InterSystems studio. Thanks I prefer editing in Visual Studio Code for two main reasons: It's available on Windows, Mac, and Linux. So I always have it available. It's a great editor for all my code - ObjectScript, JavaScript, Python, Java. https://intersystems-community.github.io/vscode-objectscript/introduction/ The reason for that will be that it is Cross Platform my friend. Visual Studio Code is supported on all the available platforms as at present. And also it has a compatibility to to edit, run and debug any version of the code that you have chosen. Ex: F#, C#, VB, Python etc. Hope this was useful and i have made it simple and clear. Thanks. We use both depending on the situation. VS Code is more modern and certainly better for Git and Merge tools than Studio but it doesn't have all the abilities of Studio that I've found, global storage properties etc. We've found VS Code doesn't handle physical files as well as Studio at least for InterSystems so its unfriendly when using CSPs that are version controlled.
Question
Rahul Srivastava · Jun 5, 2021

InterSystems IRIS Installation custom layout structure

Hello Respected members, I am new with InterSystems IRIS , want to setup the environment on RHEL 7.5 with multiple lun layouts (separate LVM for DB , Journal, and WIJ), I would like to get some help in setting up the same, as far as I know, the installation will go through on a single directory ( I did not see any option to chose path/directory for DB's or WIJ /journals), hence after installation I would like to move my DB's to separate LVM and WIJ on another LVM set Please suggest or share the steps for the same document if any for the same, that will be really helpful, Thanks Regards RS 1. Install InterSystems IRIS. 2. Shut it down. 3. Open <iris>/iris.cpf, there you will find: [Databases] USER=C:\InterSystems\IRIS\Mgr\user\ [Journal] AlternateDirectory=C:\InterSystems\IRIS\Mgr\journal\ CurrentDirectory=C:\InterSystems\IRIS\Mgr\journal\ [config] wijdir=C:\InterSystems\IRIS\Mgr\WIJ 4. Edit this file as you wish and move the corresponding directories. 5. Start InterSystems IRIS. @Eduard.Lebedyuk Thank you so much for providing this information I would like to know if I can move only user database or default databases as well?? Like irislib, irisaudit, irislocaldata and other under mgr folder Please suggest if I can do this if yes then what sort of permission do I need to change for new directory path and what all files I need to copy at new location?? I want to setup my layout as given below Database LUNs = 8 x 512GB- - - > vg_iris_db Journal LUNs = 2 x 512GB - - > vg_iris_jrn WIJ LUNs = 2 x 256GB - - > vg_iris_wij Install and IRISTEMP LUNs = 2 x 128GB - - - > vg_iris_sys Please suggest if modification in iris.cpf file can do this all operation Thanks & Regards RS I would like to know if I can move only user database or default databases as well?? All databases can be moved what sort of permission do I need to change for new directory path irisusr should have RW access to the folder. The easiest way is to check what access (owner, group, permissions) is set for existing files/folders and then recreate the same in a new location. and what all files I need to copy at new location?? IRIS.DAT and stream subfolder if it exist. Please suggest if modification in iris.cpf file can do this all operation Absolutely. @Eduard.Lebedyuk Thank you so much for providing the detailed information. I am able to deploy the IRIS Instance with custom layout which I wanted to One thing I noticed that after installation I was able to see the instance running from command line but I was unable to access management portal with the URL that comes after installation, anything I missed or need to change to make it accessible? Please suggest Thanks RS Do you get Unable to connect or something else? What's the output of iris list? Hello Rahul, I'd check your messages.log to see messages regarding the private webserver. Then I'd check the OS to see if anything is holding your configured web server port. This could be worth a new post, or contacting the WRC. I am getting below error if I tried to access the URL : This site can’t be reached scsps2391082001’s server IP address could not be found. Below is the output from iris list [root@scsps2391082001 prd]# iris list Configuration 'PROD' (default) directory: /prd versionid: 2020.1.1.408.0com datadir: /prd conf file: iris.cpf (SuperServer port = 51773, WebServer = 52773) status: running, since Thu Jun 10 05:45:18 2021 state: ok product: InterSystems IRIS[root@scsps2391082001 prd]# Below are the Installation details Please review the installation options:------------------------------------------------------------------Instance name: PRODDestination directory: /prdInterSystems IRIS version to install: 2020.1.1.408.0comInstallation type: DevelopmentUnicode support: YInitial Security settings: NormalUser who owns instance: rootGroup allowed to start and stop instance: rootEffective group for InterSystems IRIS processes: irisusrEffective user for InterSystems IRIS SuperServer: irisusrSuperServer port: 51773WebServer port: 52773JDBC Gateway port: 53773Web Gateway: using built-in web server------------------------------------------------------------------ Confirm InterSystems IRIS installation <Yes>? Starting installationStarting up InterSystems IRIS for loading...../bin/irisinstall -s . -B -c c -C /prd/iris.cpf*PROD -W 1 -g2Starting Control ProcessAllocated 159MB shared memory: 2MB global buffers, 35MB routine buffersIRIS startup successful.System locale setting is 'en_US.UTF-8'This copy of InterSystems IRIS has been licensed for use exclusively by:InterSystems IRIS CommunityCopyright (c) 1986-2021 by InterSystems CorporationAny other use is a violation of your license agreement ^^/prd/mgr/> ^^/prd/mgr/>Start of IRIS initialization Loading system routines Updating system TEMP and LOCALDATA databases Installing National Language support Setting IRISTEMP default collation to IRIS standard (5) Loading system classes Updating Security database Loading system source code Building system indices Updating Audit database Updating Journal directory Updating User database Updating Interoperability databases Scheduling inventory scan IRIS initialization complete in 2 minutes See the iboot.log file for a record of the installation. Starting up InterSystems IRIS...Once this completes, users may access InterSystems IRISStarting PRODUsing 'iris.cpf' configuration file Starting Control ProcessAutomatically configuring buffersAllocated 925MB shared memory: 725MB global buffers, 35MB routine buffersCreating a WIJ file to hold 99 megabytes of dataThis copy of InterSystems IRIS has been licensed for use exclusively by:InterSystems IRIS CommunityCopyright (c) 1986-2021 by InterSystems CorporationAny other use is a violation of your license agreement You can point your browser to http://scsps2391082001:52773/csp/sys/UtilHome.cspto access the management portal. Let me know if anything else I need to provide it as a details ? Regards RS Thanks @Vic.Sun I will create a new post and will share the messages.log entry there Thank you all for providing the inputs for my queries Regards RS Hello Rahul - I didn't see your new post yet but this message is pretty clear. The problem is at the OS level in resolving the hostname, scsps2391082001. If you replace the hostname in your URL with the actual IP of your server, it should work fine. If you want the hostname to work, I'd work with your OS/networking team to set that up.
Announcement
Anastasia Dyubaylo · Jun 21, 2021

Let's Chat: Join InterSystems Developers on Discord!

Hey Community, You've probably already heard about Discord and many of you are already chatting there. And now we invite you to become closer to the world of InterSystems technology and join the social club of our developers! Use a super-fast way to communicate with each other: 💥 InterSystems Developers Discord Channel 💥 On DC Discord Server, you'll find many InterSystems-related channels and discussions, as well as channels for everyday life conversations. Just join our club to get closer to the world of InterSystems developers! See you on the InterSystems Developers Discord ✌️ If you have any suggestions for improving our Discord Server or want to create a new channel on a specific topic – please feel free to share your thoughts in the comments. Hey everyone, To stay in touch, let's continue our tech talks on InterSystems Developers Discord Server! See you there ✌️
Announcement
Kristina Lauer · Jun 16, 2021

InterSystems IRIS® FHIR® Accelerator Learning Path

Try the new InterSystems IRIS® FHIR® Accelerator Learning Path from Online Learning. Learn the basics of this fully managed service, which allows for the storage and sharing of healthcare data via a secure and scalable FHIR® repository. Get an overview of the FHIR Accelerator Service—and see how to deploy it—by following this curated collection of multimedia resources. Target audience: Software developers and other technical audiences.
Announcement
Anastasia Dyubaylo · Jul 7, 2021

Video: What is the InterSystems IRIS FHIR Server?

Hi Developers, Learn about the InterSystems IRIS FHIR Server, the fully managed FHIR data solution that empowers FHIR application developers to focus on building life-changing healthcare applications: ⏯ What is the InterSystems IRIS FHIR Accelerator Service? Subscribe to InterSystems Developers YouTube and stay tuned!
Announcement
Anastasia Dyubaylo · Mar 8, 2021

InterSystems Grand Prix Contest: CONGRATS THE WINNERS!

Hey everyone, The InterSystems Grand Prix Contest is over. It was an incredible competition with a record number of participating apps and developers! Thank you all for participating! And now it's time to announce the winners! A storm of applause goes to these developers and their applications: 🏆 Experts Nomination - winners were determined by a specially selected jury: 🥇 1st place and $6,000 go to the vscode-intersystems-iris project by @Dmitry.Maslennikov 🥈 2nd place and $3,000 go to the iris-rad-studio project by @Henrique.GonçalvesDias and @José.Pereira 🥉 3rd place and $2,000 go to the HealthInfoQueryLayer project by @Botai.Zhang 🏆 Community Nomination - an application that received the most votes in total: 🥇 1st place and $3,000 go to the HealthInfoQueryLayer project by @Botai.Zhang 🥈 2nd place and $1,500 go to the Dictionary comparison scheme of cache database project by @Weiwei.Yang 🥉 3rd place and $500 go to the vscode-intersystems-iris project by @Dmitry.Maslennikov And... This time, we would also like to reward the developers who took 4-10 places in the Expert nomination! 10,000 points on Global Masters go to these apps and their developers: 🏅 4th place: iris-image-index-demo by @José.Pereira 🏅 5th place: Terminal Multi-Line Command Editor​​​​ by @Robert.Cemper1003 🏅 6th place: Dictionary comparison scheme of cache database by @Weiwei.Yang 🏅 7th place: Create a unified hospital data extraction scheme based on IRIS for Health by @Deming.Xu 🏅 8th place: iris4health-fhir-analytics by @José.Pereira 🏅 9th place: iris-fhir-portal by @Henrique.GonçalvesDias 🏅 10th place: ObjectScript Kernel by @Nikita.Mullin Congratulations to all the winners and participants! Thank you all for your attention to the contest and the efforts you pay in our mega competition! Congratulations to all winners! Congratulations to all winners! Congratulations to all winners! Congratulations to all winners! Congratulations! And congratulations to all the participants - that's awesome work, great applications! Big congratulations to you and @José.Pereira!!! 🤩 Hey everyone, As always, we really appreciate the contribution of all participants to the Grand Prix competition. And this time, we would also like to reward the developers who took 4-10 places in the Expert nomination! 10,000 points on Global Masters go to these apps and their developers: 🏅 4th place: iris-image-index-demo by @José.Pereira 🏅 5th place: Terminal Multi-Line Command Editor​​​​ by @Robert.Cemper1003 🏅 6th place: Dictionary comparison scheme of cache database by @Weiwei.Yang 🏅 7th place: Create a unified hospital data extraction scheme based on IRIS for Health by @Deming.Xu 🏅 8th place: iris4health-fhir-analytics by @José.Pereira 🏅 9th place: iris-fhir-portal by @Henrique.GonçalvesDias 🏅 10th place: ObjectScript Kernel by @Nikita.Mullin Thank you all! And our big congratulations! That's good news! and a real surprise! I appreciate it highly Congratulations to all winners! Thanks @Anastasia.Dyubaylo It's our pleasure to create apps that people enjoy Hey developers! We also want to thank the rest of the participants and their cool applications that were in the InterSystems Grand Prix Contest: interoperability-integratedml-adapter , iris-integratedml-monitor-example and iris-analytics-notebook by @José Roberto Pereira IRIS-REST-API-DATABASEMANAGER by @Lucas.Bourré IRIS Interoperability Message Viewer , iris-history-monitor , npm-iris and isc-generate-db by @Henrique Dias Wsock-Embedded-Py , The adopted Bitmap , Using ZPM for Node.js and WebSocket Client JS with IRIS Native API as Docker Micro Server by @Robert Cemper iris-for-money by @Oliver.Wilms springboot-iris-crud by @Yuri.Gomes Airplane React, Material UI, and REST API by @FlávioLúcio.NavesJúnior appmsw-telestat , zapm , apptools-admin and isc-apptools-lockdown by @MikhailenkoSergey realworld-intersystems-iris , isc-tar and BlocksExplorer by @Dmitry.Maslennikov RESTFUL_API_For_Hotel_OverBooking_System by @jingqi.LIu cmPurgeBackup by @Alexey.Maslov fhir-chatbot , iris-ml-suite and iris-python-suite by @Renato.Banzai IRIS import manager by @Oleh.Dontsov ISC DEV by @Gevorg.Arutiunian Questy by Alexey Nechaev M-commands instead of Excel formulas in cells by @alex.kosinets units by @Dmitrii.Kuznetsov We are waiting for your applications in the next contests🔥🔥🔥 Congratulations to all winners! Congratulations to all Congratulations to all winners ! Well done guys! I'm very proud to had been participated! Glad to see how these contests are stimulating so many people to do their best! I see those apps as ground to create awesome projects in 2021! Indeed @Robert.Cemper1003! Thank you @Anastasia.Dyubaylo ! :) Very happy to had the chance of sharing a project with @Henrique.GonçalvesDias. More brains and hands working together it's better! Congratulations to the winners for their commitment, dedication and for the work presented. certainly, that initiatives like this contribute in a unique way to the expansion of technology and all its potential.
Question
Yi Han · Mar 4, 2021

In which industries are InterSystems products used more?

InterSystems has been widely used in medical and health fields. Which other industries have high market share? What's the difference between InterSystems Trakcare and InterSystems Healthshare? we also expanding into Finance, Logistics, Government etc. Trakcare is our package HIS/EMR solution: https://www.intersystems.com/cn/products/trakcare/ HealthShare is a product family to support unified care record. For more info pls connect with our local sales team. @Jun.Qian. THX! Metallurgy, construction, clothing industry, peat extraction, trade, logistics. Also as universal system for financial and accounting for any enterprise.
Article
Guillaume Rongier · Mar 26, 2021

IAM (InterSystems API Manager), Zero to Hero

![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/introduction.png "Credit : https://blog.octo.com/kong-le-gorille-de-lapi-management-vu-de-pres/") This article contains the materials, examples, exercises to learn the basic concepts of IAM. You have all resources available on this git : https://github.com/grongierisc/iam-training. Solutions are in [training branch](https://github.com/grongierisc/iam-training/tree/training). This article will cover the following points : - [1. Introduction](#1-introduction) - [1.1. What is IAM ?](#11-what-is-iam-) - [1.2. What is an API Management ?](#12-what-is-an-api-management-) - [1.3. IAM Portal](#13-iam-portal) - [1.4. Flow of this training](#14-flow-of-this-training) - [2. Installation](#2-installation) - [2.1. What do you need to install?](#21-what-do-you-need-to-install) - [2.2. How IAM works with IRIS](#22-how-iam-works-with-iris) - [2.3. Setup](#23-setup) - [2.4. Install IAM](#24-install-iam) - [2.4.1. Iris Image](#241-iris-image) - [2.4.2. IAM Image](#242-iam-image) - [2.4.3. Update the docker file](#243-update-the-docker-file) - [2.4.4. Update the docker-compose](#244-update-the-docker-compose) - [2.4.5. Option : add IRIS_PASSWARD as .env](#245-option--add-iris_passward-as-env) - [2.4.6. Test it !](#246-test-it-) - [3. First Service/Route](#3-first-serviceroute) - [3.1. Create a service](#31-create-a-service) - [3.2. Create a route](#32-create-a-route) - [3.3. Test it !](#33-test-it-) - [4. Second, go further with plugin](#4-second-go-further-with-plugin) - [4.1. Add a plugin to the service](#41-add-a-plugin-to-the-service) - [4.2. Test it !](#42-test-it-) - [5. Third, add our own authentication](#5-third-add-our-own-authentication) - [5.1. Add consumers](#51-add-consumers) - [5.2. Add Basic auth plugin](#52-add-basic-auth-plugin) - [5.3. Add ACL Plugin](#53-add-acl-plugin) - [5.4. Configure USER with ACL and credentials](#54-configure-user-with-acl-and-credentials) - [5.5. Test it !](#55-test-it-) - [6. Exercice, Rate-Limiting](#6-exercice-rate-limiting) - [6.1. Solution](#61-solution) - [7. Dev Portal](#7-dev-portal) - [7.1. Overview](#71-overview) - [7.2. Enable it !](#72-enable-it-) - [7.3. Add your first spec](#73-add-your-first-spec) - [7.4. Test it !](#74-test-it-) - [7.5. Exercise](#75-exercise) - [7.5.1. Solution](#751-solution) - [8. Dev Portal, Part two, Authentication](#8-dev-portal-part-two-authentication) - [8.1. Enable Basic Auth](#81-enable-basic-auth) - [8.2. Limit access](#82-limit-access) - [8.2.1. Create a role](#821-create-a-role) - [8.2.2. Add role to Spec](#822-add-role-to-spec) - [8.2.3. Test it !](#823-test-it-) - [8.2.3.1. Register a new developer](#8231-register-a-new-developer) - [8.2.3.2. Approve this developer](#8232-approve-this-developer) - [8.2.3.3. Add role for this developer](#8233-add-role-for-this-developer) - [8.3. Add Oauth2 for developer](#83-add-oauth2-for-developer) - [8.3.1. First, remove basic auth](#831-first-remove-basic-auth) - [8.3.2. Second, add application-registration plugin](#832-second-add-application-registration-plugin) - [8.3.3. Link service and documentation](#833-link-service-and-documentation) - [8.3.3.1. Test it !](#8331-test-it-) - [9. Secure Management Portal](#9-secure-management-portal) - [9.1. Create an admin](#91-create-an-admin) - [9.2. Enable Basic Auth for Kong Manager](#92-enable-basic-auth-for-kong-manager) - [9.3. Use Kong Admin API with RBAC](#93-use-kong-admin-api-with-rbac) - [9.3.1. Create and admin user with a token](#931-create-and-admin-user-with-a-token) - [10. Plugins](#10-plugins) - [10.1. Import a community plugin](#101-import-a-community-plugin) - [10.1.1. Build a new Kong/IAM docker image with the community plugin](#1011-build-a-new-kongiam-docker-image-with-the-community-plugin) - [10.1.2. Test it !](#1012-test-it-) - [10.1.2.1. Use it !](#10121-use-it-) - [10.2. Create a new plugin](#102-create-a-new-plugin) - [10.2.1. File structure](#1021-file-structure) - [10.2.1.1. handler.lua](#10211-handlerlua) - [10.2.1.1.1. Example](#102111-example) - [10.2.1.2. schema.lua](#10212-schemalua) - [10.2.1.3. *.rockspec](#10213-rockspec) - [10.2.2. Build it](#1022-build-it) - [10.2.3. Tips](#1023-tips) - [11. CI/CD](#11-cicd) - [11.1. Create the postman collection](#111-create-the-postman-collection) - [11.1.1. Is IAM startup ?](#1111-is-iam-startup-) - [11.1.2. Delete old datas](#1112-delete-old-datas) - [11.1.3. Create Service/Route](#1113-create-serviceroute) - [11.1.3.1. Tips](#11131-tips) - [11.2. Run it with newman](#112-run-it-with-newman) # 1. Introduction ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/introduction.png "Credit : https://blog.octo.com/kong-le-gorille-de-lapi-management-vu-de-pres/") ## 1.1. What is IAM ? IAM stand for InterSystems API Manager, it's based on **Kong Enterprise Edition**. This mean you have access on top of Kong Open Source edition to : * Manager Portal * Developer Portal * Advance plugin * Oauth2 * Caching * ... ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/KongEEvsOSS.png) ## 1.2. What is an API Management ? API management is the process of creating and publishing web application programming interfaces (APIs), enforcing their usage policies, controlling access, nurturing the subscriber community, collecting and analyzing usage statistics, and reporting on performance. API Management components provide mechanisms and tools to support developer and subscriber community. ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/Api_Managment.png) ## 1.3. IAM Portal Kong and IAM are design as API first, this mean, everything done in Kong/IAM can be done by rest calls or the manager portal. During this article all example / exercise will present both this way: |IAM Portal|Rest API| |-----------------|--------------| |![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/default_kong.png)|![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/rest_call.png)| ## 1.4. Flow of this article The aim of this article is to use IAM as a proxy of an IRIS rest API. Definition of this rest API can be found here : ```url http://localhost:52773/swagger-ui/index.html#/ ``` or here ```url https://github.com/grongierisc/iam-training/blob/training/misc/spec.yml ``` Start this article with the main branch. At the end of the article, you should have the same result as the training branch. # 2. Installation ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/installation.png) ## 2.1. What do you need to install? * [Git](https://git-scm.com/downloads) * [Docker](https://www.docker.com/products/docker-desktop) (if you are using Windows, make sure you set your Docker installation to use "Linux containers"). * [Docker Compose](https://docs.docker.com/compose/install/) * [Visual Studio Code](https://code.visualstudio.com/download) + [InterSystems ObjectScript VSCode Extension](https://marketplace.visualstudio.com/items?itemName=daimor.vscode-objectscript) * InterSystems IRIS IAM enabled license file. * IAM Docker image ## 2.2. How IAM works with IRIS At Kong/IAM start, the container check for the Kong/IAM license with a curl call. The endpoint of this call is a rest API on the IRIS container. FYI : Kong license is embedded in IRIS one. ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/IAM_IRIS.png) ## 2.3. Setup Git clone this repository. git clone https://github.com/grongierisc/iam-training Run the initial rest API : docker-compose up Test it : ```url http://localhost:52773/swagger-ui/index.html#/ ``` Login/Password : SuperUser/SYS ## 2.4. Install IAM ### 2.4.1. Iris Image First you need to switch for the community edition to a licensed one. To do so, you need to setup your access to InterSystems Container Registry to download IRIS limited access images. Have a look at this [Introducing InterSystems Container Registry](https://community.intersystems.com/post/introducing-intersystems-container-registry) on [Developer Community](https://community.intersystems.com). * Log-in into https://containers.intersystems.com/ using your WRC credentials and get a *token*. * Set up docker login in your computer: ```bash docker login -u="user" -p="token" containers.intersystems.com ``` * Get InterSystems IRIS image: ```bash docker pull containers.intersystems.com/intersystems/irishealth:2020.4.0.524.0 ``` ### 2.4.2. IAM Image In [WRC Software Distribution](https://wrc.intersystems.com/wrc/coDistribution.csp): * Components > Download *IAM-1.5.0.9-4.tar.gz* file, unzip & untar and then load the image: ```bash docker load -i iam_image.tar ``` ### 2.4.3. Update the docker file Change IRIS community edition to a licensed one. * containers.intersystems.com/intersystems/irishealth:2020.4.0.524.0 * add iris.key in key folder Edit the dockerfile to add on top of it this part ```dockerfile ARG IMAGE=containers.intersystems.com/intersystems/irishealth:2020.4.0.524.0 # Frist stage FROM $IMAGE as iris-iam COPY key/iris.key /usr/irissys/mgr/iris.key COPY iris-iam.script /tmp/iris-iam.script RUN iris start IRIS \ && iris session IRIS < /tmp/iris-iam.script \ && iris stop IRIS quietly # Second stage FROM iris-iam ``` This part will create a multi-stage dockerfile. * the first stage is to enable IRIS to serve IAM license. * the second stage is for the REST API build Create a new file iris-iam.script to build a new IRIS Image to enable IAM endpoint and user. ```objectscript zn "%SYS" write "Create web application ...",! set webName = "/api/iam" set webProperties("Enabled") = 1 set status = ##class(Security.Applications).Modify(webName, .webProperties) write:'status $system.Status.DisplayError(status) write "Web application "_webName_" was updated!",! set userProperties("Enabled") = 1 set userName = "IAM" Do ##class(Security.Users).Modify(userName,.userProperties) write "User "_userName_" was updated!",! halt ``` ### 2.4.4. Update the docker-compose Update the docker-compose file to : * db * postgres database for IAM * iam-migration * bootstrap the database * iam * actual IAM instance * a volume for data persistent Add this part to the end of the docker-compose file. ```yml iam-migrations: image: intersystems/iam:1.5.0.9-4 command: kong migrations bootstrap up depends_on: - db environment: KONG_DATABASE: postgres KONG_PG_DATABASE: ${KONG_PG_DATABASE:-iam} KONG_PG_HOST: db KONG_PG_PASSWORD: ${KONG_PG_PASSWORD:-iam} KONG_PG_USER: ${KONG_PG_USER:-iam} KONG_CASSANDRA_CONTACT_POINTS: db KONG_PLUGINS: bundled,jwt-crafter ISC_IRIS_URL: IAM:${IRIS_PASSWORD}@iris:52773/api/iam/license restart: on-failure links: - db:db iam: image: intersystems/iam:1.5.0.9-4 depends_on: - db environment: KONG_ADMIN_ACCESS_LOG: /dev/stdout KONG_ADMIN_ERROR_LOG: /dev/stderr KONG_ADMIN_LISTEN: '0.0.0.0:8001' KONG_ANONYMOUS_REPORTS: 'off' KONG_CASSANDRA_CONTACT_POINTS: db KONG_DATABASE: postgres KONG_PG_DATABASE: ${KONG_PG_DATABASE:-iam} KONG_PG_HOST: db KONG_PG_PASSWORD: ${KONG_PG_PASSWORD:-iam} KONG_PG_USER: ${KONG_PG_USER:-iam} KONG_PROXY_ACCESS_LOG: /dev/stdout KONG_PROXY_ERROR_LOG: /dev/stderr KONG_PORTAL: 'on' KONG_PORTAL_GUI_PROTOCOL: http KONG_PORTAL_GUI_HOST: '127.0.0.1:8003' KONG_ADMIN_GUI_URL: http://localhost:8002 KONG_PLUGINS: bundled ISC_IRIS_URL: IAM:${IRIS_PASSWORD}@iris:52773/api/iam/license volumes: - ./iam:/iam links: - db:db ports: - target: 8000 published: 8000 protocol: tcp - target: 8001 published: 8001 protocol: tcp - target: 8002 published: 8002 protocol: tcp - target: 8003 published: 8003 protocol: tcp - target: 8004 published: 8004 protocol: tcp - target: 8443 published: 8443 protocol: tcp - target: 8444 published: 8444 protocol: tcp - target: 8445 published: 8445 protocol: tcp restart: on-failure db: image: postgres:9.6 environment: POSTGRES_DB: ${KONG_PG_DATABASE:-iam} POSTGRES_PASSWORD: ${KONG_PG_PASSWORD:-iam} POSTGRES_USER: ${KONG_PG_USER:-iam} volumes: - 'pgdata:/var/lib/postgresql/data' healthcheck: test: ["CMD", "pg_isready", "-U", "${KONG_PG_USER:-iam}"] interval: 30s timeout: 30s retries: 3 restart: on-failure stdin_open: true tty: true volumes: pgdata: ``` Add the .env file in root folder : ```env IRIS_PASSWORD=SYS ``` BTW : Here are the definition of Kong ports : |Port|Protocol|Description| |----|--------|-----------| |:8000|HTTP|Takes incoming HTTP traffic from Consumers, and forwards it to upstream Services.| |:8443|HTTPS|Takes incoming HTTPS traffic from Consumers, and forwards it to upstream Services.| |:8001|HTTP|Admin API. Listens for calls from the command line over HTTP.| |:8444|HTTPS|Admin API. Listens for calls from the command line over HTTPS.| |:8002|HTTP|Kong Manager (GUI). Listens for HTTP traffic.| |:8445|HTTPS|Kong Manager (GUI). Listens for HTTPS traffic.| |:8003|HTTP|Dev Portal. Listens for HTTP traffic, assuming Dev Portal is enabled.| |:8446|HTTPS|Dev Portal. Listens for HTTPS traffic, assuming Dev Portal is enabled.| |:8004|HTTP|Dev Portal /files traffic over HTTP, assuming the Dev Portal is enabled.| |:8447|HTTPS|Dev Portal /files traffic over HTTPS, assuming the Dev Portal is enabled.| ### 2.4.5. Option : add IRIS_PASSWARD as .env For ease of use (and may be security), you can use the .env file in the IRIS dockerfile. To do so, edit the docker-compose with this in the iris service part : ```yml build: context: . dockerfile: dockerfile args: - IRIS_PASSWORD=${IRIS_PASSWORD} ``` And the dockerfile (second or first stage of the build): ```dockerfile ARG IRIS_PASSWORD RUN echo "${IRIS_PASSWORD}" > /tmp/password.txt && /usr/irissys/dev/Container/changePassword.sh /tmp/password.txt ``` ### 2.4.6. Test it ! docker-compose -f "docker-compose.yml" up -d --build # 3. First Service/Route ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/service_route.png) Remember how Kong/IAM works ? ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/KongEEvsOSS.png) Here, we will build : * a service * for our crud API * a route * to access this service ## 3.1. Create a service IAM Portal Rest API # Create service curl -i -X POST \ --url http://localhost:8001/services/ \ --data 'name=crud' \ --data 'url=http://iris:52773/crud/' What do we see here, to create a service we simply need it's url. ## 3.2. Create a route IAM Portal Rest API # Create route curl -i -X POST \ --url http://localhost:8001/services/crud/routes \ --data 'name=crud-route' \ --data 'paths=/persons/*' \ --data 'strip_path=false' What do we see here, to create a route we need : * it's service name * a path where RegEx is allowed ## 3.3. Test it ! **Original API** # Legacy curl –i --location --request GET 'http://localhost:52773/crud/persons/all' \ --header 'Authorization: Basic U3VwZXJVc2VyOlNZUw==' **Proxy API** # KONG curl –i --location --request GET 'http://localhost:8000/persons/all' \ --header 'Authorization: Basic U3VwZXJVc2VyOlNZUw==' What do we see here : * Nothing new on legacy side. * On kong side : * We change the port * The path corresponds to the route * We still need to authenticate # 4. Second, go further with plugin To go further, we will try to auto-authenticate Kong to the IRIS endpoint. To do so, we will use and plugin, resquest-transformer. ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/auto_authenticate.png) ## 4.1. Add a plugin to the service IAM Portal Rest API # Create plugin curl -i -X POST \ --url http://localhost:8001/services/crud/plugins \ --data 'name=request-transformer' \ --data 'config.add.headers=Authorization:Basic U3VwZXJVc2VyOlNZUw==' \ --data 'config.replace.headers=Authorization:Basic U3VwZXJVc2VyOlNZUw==' ## 4.2. Test it ! # Legacy **Original API** curl –i --location --request GET 'http://localhost:52773/crud/persons/all' **Proxy API** # KONG curl –i --location --request GET 'http://localhost:8000/persons/all' What do we see here : * Error 401 on the original API * We reach the data without authentication # 5. Third, add our own authentication What we want to achieved here is to add our own authentication without any distuption of the original API. ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/custom_auth.png) ## 5.1. Add consumers IAM Portal Rest API # Add consumer anonymous curl -i -X POST \ --url http://localhost:8001/consumers/ \ --data "username=anonymous" \ --data "custom_id=anonymous" # Add consumer user curl -i -X POST \ --url http://localhost:8001/consumers/ \ --data "username=user" \ --data "custom_id=user" ## 5.2. Add Basic auth plugin IAM Portal Rest API # Enable basic auth for service curl -i -X POST http://localhost:8001/routes/crud-route/plugins \ --data "name=basic-auth" \ --data "config.anonymous=5cc8dee4-066d-492e-b2f8-bd77eb0a4c86" \ --data "config.hide_credentials=false" Where : * config.anonymous = uuid of anonymous consumer ## 5.3. Add ACL Plugin IAM Portal Rest API # Enable ACL curl -i -X POST http://localhost:8001/routes/crud-route/plugins \ --data "name=acl" \ --data "config.whitelist=user" ## 5.4. Configure USER with ACL and credentials IAM Portal Rest API # Add consumer group curl -i -X POST \ --url http://localhost:8001/consumers/user/acls \ --data "group=user" # Add consumer credentials curl -i -X POST http://localhost:8001/consumers/user/basic-auth \ --data "username=user" \ --data "password=user" ## 5.5. Test it ! **Original API** # Legacy curl –i --location --request GET 'http://localhost:52773/crud/persons/all' \ --header 'Authorization:Basic dXNlcjp1c2Vy' **Proxy API ** # KONG curl –i --location --request GET 'http://localhost:8000/persons/all' \ --header 'Authorization:Basic dXNlcjp1c2Vy' # 6. Exercice, Rate-Limiting 1. Enable Unauthenticated user 2. Limit rate by 2 calls per minutes to Unauthenticated user ## 6.1. Solution 1. Enable Unauthenticated user IAM Portal Rest API # Add consumer group curl -i -X POST \ --url http://localhost:8001/consumers/anonymous/acls \ --data "group=user" 2. Limit rate by 2 calls per minutes to Unauthenticated user IAM Portal Rest API # Add rate limit consumer curl -i -X POST \ --url http://localhost:8001/consumers/anonymous/plugins \ --data "name=rate-limiting" \ --data "config.limit_by=consumer" \ --data "config.minute=2" # 7. Dev Portal ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/dev_portal_intro.png) ## 7.1. Overview The Kong Developer Portal provides : * a single source of truth for all developers * intuitive content management for documentation * streamlined developer onboarding * role-based access control (RBAC) ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/dev_portal.png) ## 7.2. Enable it ! IAM Portal Rest API curl -X PATCH http://localhost:8001/workspaces/default --data "config.portal=true" ## 7.3. Add your first spec **IAM Portal** **Rest API** curl -X POST http://localhost:8001/default/files -F "path=specs/iam-training.yml" -F "contents=@misc/spec.yml" ## 7.4. Test it ! ```url http://localhost:8003/default/documentation/iam-training ``` What happen ? How-to solve it ? ## 7.5. Exercise 1. Add CORS plugin on route ### 7.5.1. Solution IAM Portal Rest API # Enable CORS curl -i -X POST http://localhost:8001/routes/crud-route/plugins \ --data "name=cors" # 8. Dev Portal, Part two, Authentication ## 8.1. Enable Basic Auth IAM Portal Session Config (JSON) { "cookie_secure": false, "cookie_name": "portal_session", "secret": "SYS", "storage": "kong" } Now authentication is enabled for the dev portal. ## 8.2. Limit access By default, all is accessible for unauthenticated user. We can create role to limit some access. For example, let restrict access to our CRUD API documentation. ### 8.2.1. Create a role IAM Portal Rest API # Enable role curl -i -X POST http://localhost:8001/default/developers/roles \ --data "name=dev" ### 8.2.2. Add role to Spec **IAM Portal** **Rest API** # Enable role curl 'http://localhost:8001/default/files/specs/iam-training.yml' -X PATCH -H 'Accept: application/json, text/plain, */*' --compressed -H 'Content-Type: application/json;charset=utf-8' -H 'Origin: http://localhost:8002' -H 'Referer: http://localhost:8002/default/portal/permissions/' --data-raw $'{"contents":"x-headmatter:\\n readable_by:\\n - dev\\nswagger: \'2.0\'\\ninfo:\\n title: InterSystems IRIS REST CRUD demo\\n description: Demo of a simple rest API on IRIS\\n version: \'0.1\'\\n contact:\\n email: apiteam@swagger.io\\n license:\\n name: Apache 2.0\\n url: \'http://www.apache.org/licenses/LICENSE-2.0.html\'\\nhost: \'localhost:8000\'\\nbasePath: /\\nschemes:\\n - http\\nsecurityDefinitions:\\n basicAuth:\\n type: basic\\nsecurity:\\n - basicAuth: []\\npaths:\\n /:\\n get:\\n description: \' PersonsREST general information \'\\n summary: \' Server Info \'\\n operationId: GetInfo\\n x-ISC_CORS: true\\n x-ISC_ServiceMethod: GetInfo\\n responses:\\n \'200\':\\n description: (Expected Result)\\n schema:\\n type: object\\n properties:\\n version:\\n type: string\\n default:\\n description: (Unexpected Error)\\n /persons/all:\\n get:\\n description: \' Retreive all the records of Sample.Person \'\\n summary: \' Get all records of Person class \'\\n operationId: GetAllPersons\\n x-ISC_ServiceMethod: GetAllPersons\\n responses:\\n \'200\':\\n description: (Expected Result)\\n schema:\\n type: array\\n items:\\n $ref: \'#/definitions/Person\'\\n default:\\n description: (Unexpected Error)\\n \'/persons/{id}\':\\n get:\\n description: \' Return one record fo Sample.Person \'\\n summary: \' GET method to return JSON for a given person id\'\\n operationId: GetPerson\\n x-ISC_ServiceMethod: GetPerson\\n parameters:\\n - name: id\\n in: path\\n required: true\\n type: string\\n responses:\\n \'200\':\\n description: (Expected Result)\\n schema:\\n $ref: \'#/definitions/Person\'\\n default:\\n description: (Unexpected Error)\\n put:\\n description: \' Update a record in Sample.Person with id \'\\n summary: \' Update a person with id\'\\n operationId: UpdatePerson\\n x-ISC_ServiceMethod: UpdatePerson\\n parameters:\\n - name: id\\n in: path\\n required: true\\n type: string\\n - name: payloadBody\\n in: body\\n description: Request body contents\\n required: false\\n schema:\\n type: string\\n responses:\\n \'200\':\\n description: (Expected Result)\\n default:\\n description: (Unexpected Error)\\n delete:\\n description: \' Delete a record with id in Sample.Person \'\\n summary: \' Delete a person with id\'\\n operationId: DeletePerson\\n x-ISC_ServiceMethod: DeletePerson\\n parameters:\\n - name: id\\n in: path\\n required: true\\n type: string\\n responses:\\n \'200\':\\n description: (Expected Result)\\n default:\\n description: (Unexpected Error)\\n /persons/:\\n post:\\n description: \' Creates a new Sample.Person record \'\\n summary: \' Create a person\'\\n operationId: CreatePerson\\n x-ISC_ServiceMethod: CreatePerson\\n parameters:\\n - name: payloadBody\\n in: body\\n description: Request body contents\\n required: false\\n schema:\\n type: string\\n responses:\\n \'200\':\\n description: (Expected Result)\\n default:\\n description: (Unexpected Error)\\ndefinitions:\\n Person:\\n type: object\\n properties:\\n Name:\\n type: string\\n Title:\\n type: string\\n Company:\\n type: string\\n Phone:\\n type: string\\n DOB:\\n type: string\\n format: date-time\\n"}' What's important here is this part : ```yml x-headmatter: readable_by: - dev ``` Refere to this documentation : [readable_by attribute](https://docs.konghq.com/enterprise/1.5.x/developer-portal/administration/developer-permissions/#readable_by-attribute) ### 8.2.3. Test it ! #### 8.2.3.1. Register a new developer ![video](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/video/new_dev_sign.gif) #### 8.2.3.2. Approve this developer ![video](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/video/approve_new_dev.gif) #### 8.2.3.3. Add role for this developer ![video](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/video/add_role_dev.gif) curl 'http://localhost:8001/default/developers/dev@dev.com' -X PATCH --compressed -H 'Content-Type: application/json;charset=utf-8' -H 'Cache-Control: no-cache' -H 'Origin: http://localhost:8002' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Referer: http://localhost:8002/default/portal/permissions/dev/update' -H 'Pragma: no-cache' --data-raw '{"roles":["dev"]}' ## 8.3. Add Oauth2 for developer In this part we will add an Oauth2 authentication for developers to use securely our crud API. This flow will provide self-registration from developer and grant them access to the crud API. ### 8.3.1. First, remove basic auth To do so, we will replace our basic auth to a bearToken one. First disable our basic auth/acl. **IAM Portal** **Rest API** # Disable ACL Plugin curl 'http://localhost:8001/default/routes/afefe836-b9be-49a8-927a-1324a8597a9c/plugins/3f2e605e-9cb6-454a-83ec-d1b1929b1d30' -X PATCH --compressed -H 'Content-Type: application/json;charset=utf-8' -H 'Cache-Control: no-cache' -H 'Origin: http://localhost:8002' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Referer: http://localhost:8002/default/plugins/acl/3f2e605e-9cb6-454a-83ec-d1b1929b1d30/update' -H 'Pragma: no-cache' --data-raw '{"enabled":false,"name":"acl","route":{"id":"afefe836-b9be-49a8-927a-1324a8597a9c"},"config":{"hide_groups_header":false,"whitelist":["user","dev","crud"]}}' ### 8.3.2. Second, add application-registration plugin IAM Portal Rest API # Create application-registration plugin curl -i -X POST \ --url http://localhost:8001/services/crud/plugins \ --data 'name=application-registration' \ --data 'config.auth_header_name=authorization' \ --data 'config.auto_approve=true' \ --data 'config.display_name=auth' \ --data 'config.enable_client_credentials=true' ### 8.3.3. Link service and documentation **IAM Porta** **Rest API** curl 'http://localhost:8001/default/document_objects' --compressed -H 'Content-Type: application/json;charset=utf-8' -H 'Cache-Control: no-cache' -H 'Origin: http://localhost:8002' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Referer: http://localhost:8002/default/services/create-documentation' -H 'Pragma: no-cache' --data-raw '{"service":{"id":"7bcef2e6-117c-487a-aab2-c7e57a0bf61a"},"path":"specs/iam-training.yml"}' #### 8.3.3.1. Test it ! From the dev portal logged as dev@dev.com, create a new application. ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/video/add_app_dev.gif) This will give you client_id and client_secret. Theses can be used in the swagger dev portal. Register this application to the crud service : ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/video/register_app_dev.gif) Get token: curl --insecure -X POST https://localhost:8443/persons/oauth2/token \ --data "grant_type=client_credentials" \ --data "client_id=2TXNvDqjeVMHydJbjv9t96lWTXOKAtU8" \ --data "client_secret=V6Vma6AtIvl04UYssz6gAxPc92eCF4KR" Use token : curl --insecure -X GET https://localhost:8443/persons/all \ --header "authorization: Bearer u5guWaYR3BjZ1KdwuBSC6C7udCYxj5vK" # 9. Secure Management Portal ## 9.1. Create an admin As we have bootstrap Kong without a seed password. We have to create an admin before enforcing RBAC. To do so: * Go to Teams * Invite admin * Set Mail * Set Username * Set role to super admin * Invite * Go to Invited Admin * View * Generate link ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/video/invite_admin.gif) ## 9.2. Enable Basic Auth for Kong Manager To enable this feature, we have to change the docker-compose file. Add this to the iam service, environment ```yml KONG_ENFORCE_RBAC: 'on' KONG_ADMIN_GUI_AUTH: 'basic-auth' KONG_ADMIN_GUI_SESSION_CONF: '{"secret":"${IRIS_PASSWORD}","storage":"kong","cookie_secure":false}' ``` Restart the container docker-compose down && docker-compose up -d Go to the invited admin link : ```url http://localhost:8002/register?email=test.test%40gmail.com&username=admin&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTYzMzYzNzEsImlkIjoiY2JiZGE5Y2UtODQ3NS00MmM2LTk4ZjItNDgwZTI4MjQ4NWNkIn0.sFeOc_5UPIr3MdlQrgyGvmvIjRFvSn3nQjo2ph8GrJA ``` ## 9.3. Use Kong Admin API with RBAC As RBAC is set, we can't use kong admin api anymore : curl -s -X GET \ --url http://localhost:8001/routes Get this error : ```json {"message":"Invalid credentials. Token or User credentials required"} ``` ### 9.3.1. Create and admin user with a token * Go to Teams * RBAC Users * Add new user ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/user_rbac.png) curl -s -X GET \ --url http://localhost:8001/routes \ --header "Kong-Admin-Token: SYS" # 10. Plugins ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/plugins_intro.png) Kong come with high quality plugins. But, what if, we need plugin that are not embedded. If we want community plugins ? In this chapiter, we will talk about community plugins, how to import them. Then, we will see how-to build our own plugin. ## 10.1. Import a community plugin For this part, we will be using the jwt-crafter plugin. This plugin adds the possibility to generate a JWT token within Kong itself, eliminating the need for an upstream service doing the token generation. Here is the plugin : ``` https://github.com/grongierisc/kong-plugin-jwt-crafter ``` To install this plugin, as we are using the docker version, we have to build a new image who embed the plugin. ### 10.1.1. Build a new Kong/IAM docker image with the community plugin 1. Create a folder named iam at root of this git. 2. Create a dockerfile in this new folder 3. Create a folder named plugins 1. This is where we will add all our community plugins 4. Update the docker-compose file to enable the new plug in In the plugins folder, git clone our community plugin. git clone https://github.com/grongierisc/kong-plugin-jwt-crafter The dockerfile should look like this: ```dockerfile FROM intersystems/iam:1.5.0.9-4 USER root COPY ./plugins /custom/plugins RUN cd /custom/plugins/kong-plugin-jwt-crafter && luarocks make USER kong ``` What we see in this dockerfile ? Simply to install a community plugin, we have to move to its root folder (where the rockspec is) and call luarocks make. That's it. You have installed the plugin. For the docker-compose part : 1. Edit the iam iamge tag 1. intersystems/iam:1.5.0.9-4 -> intersystems/iam-custom:1.5.0.9-4 2. Add a build context ```yml build: context: iam dockerfile: dockerfile ``` 3. Enable the plugin in the environment variables ```yml KONG_PLUGINS: 'bundled,jwt-crafter' ``` Now build our new iam image : docker-compose build iam ### 10.1.2. Test it ! docker-compose up -d If you go to plugin -> new, at the bottom of the list you should see the jwt-crafter plugin. ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/jwt_crafter.png) #### 10.1.2.1. Use it ! 1. Create a new service : IAM Portal Rest API # Create service curl -i -X POST \ --url http://localhost:8001/services/ \ --data 'name=crud-persons' \ --data 'url=http://iris:52773/crud/persons/' 2. Create a route IAM Portal Rest API # Create route curl -i -X POST \ --url http://localhost:8001/services/crud-persons/routes \ --data 'name=crud-route-jwt' \ --data 'paths=/crud/persons/*' \ --data 'strip_path=true' 3. Re-use our auto-auth IAM Portal Rest API # Create plugin curl -i -X POST \ --url http://localhost:8001/services/crud-persons/plugins \ --data 'name=request-transformer' \ --data 'config.add.headers=Authorization:Basic U3VwZXJVc2VyOlNZUw==' \ --data 'config.replace.headers=Authorization:Basic U3VwZXJVc2VyOlNZUw==' Now we are set. The real use of jwt-crafter. ```bash # Add acl to route curl -i -X POST http://localhost:8001/routes/crud-route-jwt/plugins \ --data "name=acl" \ --data "config.whitelist=test" \ --data "config.hide_groups_header=false" # Create service curl -i -X POST \ --url http://localhost:8001/services/ \ --data 'name=jwt-login' \ --data 'url=http://neverinvoked/' # Create route curl -i -X POST \ --url http://localhost:8001/services/jwt-login/routes \ --data 'name=jwt-login-route' \ --data 'paths=/jwt/log-in' # Enable basic auth for service curl -i -X POST http://localhost:8001/routes/jwt-login-route/plugins \ --data "name=basic-auth" \ --data "config.hide_credentials=false" # Enable basic auth for service curl -i -X POST http://localhost:8001/routes/jwt-login-route/plugins \ --data "name=jwt-crafter" \ --data "config.expires_in=86400" # Add consumer curl -i -X POST \ --url http://localhost:8001/consumers/ \ --data "username=test" # Add consumer group curl -i -X POST \ --url http://localhost:8001/consumers/test/acls \ --data "group=test" # Add consumer credentials curl -i -X POST http://localhost:8001/consumers/test/basic-auth \ --data "username=test" \ --data "password=test" curl -i -X POST http://localhost:8001/consumers/test/jwt \ --data "key=test" \ --data "algorithm=HS256" # JWT plugins curl -i -X POST http://localhost:8001/routes/crud-route-jwt/plugins \ --data "name=jwt" ``` Test it ! ```bash # test:test is base64 encoded curl -H 'Authorization: basic dGVzdDp0ZXN0' localhost:8000/jwt/log-in ``` ```bash curl --location --request GET 'http://localhost:8000/crud/persons/all' \ --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW0iOiJ0ZXN0Iiwic3ViIjoiODJiNjcwZDgtNmY2OC00NDE5LWJiMmMtMmYxZjMxNTViN2E2Iiwicm9sIjpbInRlc3QiXSwiZXhwIjoxNjE2MjUyMTIwLCJpc3MiOiJ0ZXN0In0.g2jFqe0hDPumy8_gG7J3nYsuZ8KUz9SgZOecdBDhfns' ``` ## 10.2. Create a new plugin This is not the place to learn lua. But I'll give you some tips like how to quickly restart IAM to test our new development. ### 10.2.1. File structure ``` kong-plugin-helloworld ├── kong │ └── plugins │ └── helloworld │ ├── handler.lua │ └── schema.lua └── kong-plugin-helloworld-0.1.0-1.rockspec ``` By convention, kong plugins must be prefix by kong-plugin. In our example, the name of the plugin is helloworld. Three files are mandatory : * handler.lua: the core of your plugin. It is an interface to implement, in which each function will be run at the desired moment in the lifecycle of a request / connection. * schema.lua: your plugin probably has to retain some configuration entered by the user. This module holds the schema of that configuration and defines rules on it, so that the user can only enter valid configuration values. * *.rockspec: Rockspec: a package specification file A declarative Lua script, with rules on how to build and package rocks *.rockspec - a Lua file containing some tables. #### 10.2.1.1. handler.lua The plugins interface allows you to override any of the following methods in your handler.lua file to implement custom logic at various entry-points of the execution life-cycle of Kong: |Function name |Phase |Description| |----|----|----| |:init_worker() |init_worker |Executed upon every Nginx worker process’s startup.| |:certificate() |ssl_certificate |Executed during the SSL certificate serving phase of the SSL handshake.| |:rewrite() |rewrite |Executed for every request upon its reception from a client as a rewrite phase handler. NOTE in this phase neither the Service nor the Consumer have been identified, hence this handler will only be executed if the plugin was configured as a global plugin!| |:access() |access |Executed for every request from a client and before it is being proxied to the upstream service.| |:response() |access |Replaces both header_filter() and body_filter(). Executed after the whole response has been received from the upstream service, but before sending any part of it to the client.| |:header_filter() |header_filter |Executed when all response headers bytes have been received from the upstream service.| |:body_filter() |body_filter |Executed for each chunk of the response body received from the upstream service. Since the response is streamed back to the client, it can exceed the buffer size and be streamed chunk by chunk. hence this method can be called multiple times if the response is large. See the lua-nginx-module documentation for more details.| |:log() |log |Executed when the last response byte has been sent to the client.| ##### 10.2.1.1.1. Example ```lua local BasePlugin = require "kong.plugins.base_plugin" local HelloWorldHandler = BasePlugin:extend() function HelloWorldHandler:new() HelloWorldHandler.super.new(self, "helloworld") end function HelloWorldHandler:access(conf) HelloWorldHandler.super.access(self) if conf.say_hello then ngx.log(ngx.ERR, "============ Hello World! ============") ngx.header["Hello-World"] = "Hello World!!!" else ngx.log(ngx.ERR, "============ Bye World! ============") ngx.header["Hello-World"] = "Bye World!!!" end end return HelloWorldHandler ``` #### 10.2.1.2. schema.lua Simply the configuration file see in the portal. ```lua return { no_consumer = true, fields = { say_hello = { type = "boolean", default = true }, say_hello_body = { type = "boolean", default = true } } } ``` #### 10.2.1.3. *.rockspec ```rockspec package = "kong-plugin-helloworld" -- hint: rename, must match the info in the filename of this rockspec! -- as a convention; stick to the prefix: `kong-plugin-` version = "0.1.0-1" -- hint: renumber, must match the info in the filename of this rockspec! -- The version '0.1.0' is the source code version, the trailing '1' is the version of this rockspec. -- whenever the source version changes, the rockspec should be reset to 1. The rockspec version is only -- updated (incremented) when this file changes, but the source remains the same. -- TODO: This is the name to set in the Kong configuration `plugins` setting. -- Here we extract it from the package name. local pluginName = package:match("^kong%-plugin%-(.+)$") -- "myPlugin" supported_platforms = {"linux", "macosx"} source = { url = "https://github.com/grongierisc/iam-training", branch = "master", -- tag = "0.1.0" -- hint: "tag" could be used to match tag in the repository } description = { summary = "This a demo helloworld for Kong plugin", homepage = "https://github.com/grongierisc/iam-training", license = "Apache 2.0" } dependencies = { "lua >= 5.1" -- other dependencies should appear here } build = { type = "builtin", modules = { ["kong.plugins."..pluginName..".handler"] = "kong/plugins/"..pluginName.."/handler.lua", ["kong.plugins."..pluginName..".schema"] = "kong/plugins/"..pluginName.."/schema.lua", } } ``` ### 10.2.2. Build it We will be doing the same as here : [11.1.1. Build a new Kong/IAM docker image with the community plugin](#1111-build-a-new-kongiam-docker-image-with-the-community-plugin) But adapted to our plugin : Dockerfile : ```dockerfile FROM intersystems/iam:1.5.0.9-4 USER root COPY ./plugins /custom/plugins RUN cd /custom/plugins/kong-plugin-jwt-crafter && luarocks make RUN cd /custom/plugins/kong-plugin-helloworld && luarocks make #USER kong #Stay with root use, we will see why later ``` Enable the plugin in the environment variables ```yml KONG_PLUGINS: 'bundled,jwt-crafter,helloworld' ``` Now build our new iam image : docker-compose build iam Then docker-compose up and test it. ### 10.2.3. Tips To run the IAM container in "debug mode", to easily stop/restart it, modify the dockerfile to add/remove plugin and so on. You can stop iam service : docker-compose stop iam And start it in run mode with a shell : docker-compose run -p 8000:8000 -p 8001:8001 -p 8002:8002 iam sh In the container : ./docker-entrypoint.sh kong Happy coding :) # 11. CI/CD ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/cd_ci_intro.png) We are close to the end of this article. To finish let's talk about DevOps/CI/CD. The aim of this chapter is to give you some ideas about how to implement/script ci/cd for IAM/Kong. As Kong is API first, the idea is to script all the rest calls and play then on each environment. The easiest way to script rest calls is with postman and his best friend newman (command line version of postman). ## 11.1. Create the postman collection One thing handy with postman is its ability to run script before and after a rest call. We will use this functionality in most cases. ### 11.1.1. Is IAM startup ? Our first script will check if IAM is up and running. ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/postman_startup.png) ```javascript var iam_url = pm.environment.get("iam_url"); var iam_config_port = pm.environment.get("iam_config_port"); var url = "http://" + iam_url + ":" + iam_config_port + "/"; SenReq(20); async function SenReq(maxRequest) { var next_request = "end request"; const result = await SendRequest(maxRequest); console.log("result:",result); if(result == -1) { console.error("IAM starting .... failed !!!!"); } } function SendRequest(maxRequest) { return new Promise(resolve => { pm.sendRequest(url, function (err) { if (err) { if (maxRequest > 1) { setTimeout(function () {}, 5000); console.warn("IAM not started...retry..next retry in 5 sec"); SendRequest(maxRequest - 1); } else { console.error("IAM starting .... failed"); resolve(-1); } } else { console.log("IAM starting .... ok"); resolve(1); } } ); }); } ``` ### 11.1.2. Delete old datas ```javascript var iam_url=pm.environment.get("iam_url"); var iam_config_port=pm.environment.get("iam_config_port"); pm.sendRequest("http://"+iam_url+":"+iam_config_port+"/plugins", function (err, res) { if (err) { console.log("ERROR : ",err); } else { var body_json=res.json(); if(body_json.data) { for( i=0; i < body_json.data.length; i++) { // Example with a full fledged SDK Request route_id = body_json.data[i].id; const delete_route = { url: "http://"+iam_url+":"+iam_config_port+"/plugins/" + route_id, method: 'DELETE', }; pm.sendRequest(delete_route, function(err, res){ console.log(err ? err : res); }); } } } }); ``` Do the same for routes, services and consumers. This order is important beause you can't remove services with routes. ### 11.1.3. Create Service/Route Routes are dependent from services. For this type of cases we can use Test function of postman to retrieve data : ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/postman_form_data.png) Screen Script var id = pm.response.json().id; var name = pm.response.json().name; pm.globals.set("service_crud_id", id); pm.globals.set("service_crud_name", name); Here we save from the response the id and name of the new services. Then we can use it in the next route creation : Screen Script service_crud_name = pm.globals.get("service_crud_name"); Here we retrieve the global variable "service_crud_name". Then, use it in the actual call. Screen Script { "paths": [ "/persons/*" ], "protocols": [ "http" ], "name": "crud-persons", "strip_path": false, "service": { "name": "{{service_crud_name}}" } } #### 11.1.3.1. Tips * paylaod can be either json or form-data * form-data : ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/postman_form_data.png) * json : ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/postman_json.png) Easy way to get the json format, go to the manager portal, view, copy json : ![alt](https://raw.githubusercontent.com/grongierisc/iam-training/training/misc/img/postman_get_json.png) ## 11.2. Run it with newman docker run --rm -v "`pwd`/ci/":"/etc/newman" \ --network="iam-training_default" \ -t postman/newman run "DevOps_IAM.postman_collection.json" \ --environment="DevOps_IAM.postman_environment.json"
Announcement
Evgeny Shvarov · Mar 26, 2021

Bonus Points for InterSystems Developer Tools Contest

Hi Developers! Here're the technology bonuses for the InterSystems Developer Tools Contest that will give you extra points in the voting. Docker container usage - 2 points The application gets a 'Docker container' bonus if it uses InterSystems IRIS running in a docker container. Here is the simplest template to start from. ZPM Package deployment - 2 points You can collect the bonus if you build and publish the ZPM(ObjectScript Package Manager) package for your Full-Stack application so it could be deployed with: zpm "install your-multi-model-solution" command on IRIS with ZPM client installed. ZPM client. Documentation. Unit Testing - 2 points Applications that have Unit Testing for the InterSystems IRIS code will collect the bonus. Learn more about ObjectScript Unit Testing in Documentation and on Developer Community. Online Demo of your project - 3 pointsCollect 3 more bonus points if you provision your project to the cloud as an online demo. You can use this template or any other deployment option. Example. Learn more on deployment in Monday's Kick-Off webinar. Code quality analysis with zero bugs - 2 points Include the code quality Github action for code static control and make it show 0 bugs for ObjectScript. Learn more in Monday's Kick-Off webinar. Article on Developer Community - 2 points Post an article on Developer Community that describes features of your project. Collect 2 points for each article. Translations to different languages work too. Video on YouTube - 3 points Make the Youtube video that demonstrates your product in action and collect 3 bonus points per each. Example. The list of bonuses is subject to change. Stay tuned!
Article
Bob Binstock · Apr 26, 2021

Scaling Cloud Hosts and Reconfiguring InterSystems IRIS

Like hardware hosts, virtual hosts in public and private clouds can develop resource bottlenecks as workloads increase. If you are using and managing InterSystems IRIS instances deployed in public or private clouds, you may have encountered a situation in which addressing performance or other issues requires increasing the capacity of an instance's host (that is, vertically scaling). One common reason to scale is insufficient memory. As described in Memory Management and Scaling for InterSystems IRIS in the Scalability Guide, providing enough memory for all of the entities running on the host of an InterSystems IRIS instance under all normal operating circumstances is a critical factor in both performance and availability. In one common scenario, as the workload of an InterSystems IRIS instance increases, its working set becomes too large to be held by the instance's allocated database cache. This forces some queries to fall back to disk, greatly increasing the number of disk reads required and creating a major performance problem. Increasing the size of the cache solves that problem, but if doing so would leave insufficient memory remaining for other purposes, you also need to increase the total physical memory on the host to avoid pushing the bottleneck to another part of the system. Fortunately, scaling a virtual host is typically a lot easier than scaling hardware. This post discusses the two stages of the process: Scaling the cloud host's resources You can change the resource specification of a virtual host on AWS, GCP, and Azure, using the platform's command line, API, or portal. VMWare vSphere allows you to easily change a number of resource parameters for a VM through its vSphere Client interface.. Reconfiguring InterSystems IRIS to take advantage of the scaled resources There are a number of ways to reconfigure InterSystems IRIS to take advantage of scaled host resources. This document describes the use of the configuration merge feature, which merges new parameter values, specified in a merge file, into an instance's CPF. Configuration merge is an easy and effective method because it lets you address only the configuration settings you want to modify, make multiple changes to an instance's configuration in one operation, and easily make the same set of changes to multiple instances. The procedures described here are manual, but in production they would very likely be automated, for example using a script that would apply a specific merge file in an accessible location to a list of instances. Scaling Cloud Host Resources Public cloud platforms provide a range of resource templates to choose from that specify CPU, memory, network interfaces, and other resources for virtual hosts (storage is provisioned and sized separately). To resize a host, you change the template selected when the host was provisioned to one that specifies more of the resources you want to increase. On Amazon Web Services, the resource template is called an instance type; for example, the t3.large instance type specifies 2 CPUs and 8 GB of memory. On Google Cloud Platform it's a machine type, such as the e2-standard-2 (which also includes 2 CPUs and 8 GB), and on Microsoft Azure it's a size (the Standard_B2ms calls for the same 2 CPUs and 8 GB). By redefining the instance type, machine type, or size of an existing public cloud host, you can scale its resource specifications. In a VMware vSphere private cloud, you can use the vSphere Client interface to the vCenter Server management console to directly modify one or more individual resource settings of an existing virtual machine. (You can also simultaneously scale groups of hosts on each platform.) The following sections provide brief examples of resizing individual virtual hosts on the various platforms, with links to the documentation for all available methods. Please note that these methods (APIs, command line interfaces, and portal interfaces) are offered and maintained by the cloud vendors, and the examples included here are for informational purposes, to illustrate how easily you can adapt InterSystems IRIS to take advantage of increased resources AWS To modify the instance type of an AWS host (called an instance, not to be confused with an InterSystems IRIS instance), you can use the modify-instance-attribute CLI command, as shown in the following example: $ aws ec2 describe-instances --instance-ids i-01519f663af48a55e { "Instances": [ { "AmiLaunchIndex": 0, "ImageId": "ami-0abcdef1234567890, "InstanceId": "i-1234567890abcdef0, "InstanceType": "m5n.large", ... $ aws ec2 stop-instances --instance-ids i-01519f663af48a55e { "StoppingInstances": [ { "InstanceId": "i-1234567890abcdef0", ... $ aws ec2 describe-instances --instance-ids i-01519f663af48a55e { "Instances": [ { ... "State": { "Code": 80, "Name": "stopped" } ... $ aws ec2 modify-instance-attribute --instance-ids i-01519f663af48a55e \ --instance-type "{\"Value\": \"m5n.xlarge\"}" $ aws ec2 start-instances --instance-ids i-01519f663af48a55e { "StartingInstances": [ { "InstanceId": "i-1234567890abcdef0", "CurrentState": { "Code": 0, "Name": "pending" }, "PreviousState": { "Code": 80, "Name": "stopped" ... $ aws ec2 describe-instances --instance-ids i-01519f663af48a55e { "Instances": [ { "AmiLaunchIndex": 0, "ImageId": "ami-0abcdef1234567890, "InstanceId": "i-1234567890abcdef0, "InstanceType": "m5n.xlarge", ... You can also make this change using the ModifyInstanceAttribute AWS API call or the AWS EC2 console. GCP To modify the machine type of a GCP host (also known as an instance), you can use the gcloud CLI to stop, modify, and restart the instance. For example, you would use the following commands to change the machine type of an instance named scalingTest to n1-highmem-96: $ gcloud compute instances stop scalingTest $ gcloud compute instances set-machine-type scalingTest --machine-type n1-highmem-32 $ gcloud compute instances start scalingTest You can also make this change using the Google Cloud Console or GCP API. Azure When you use the Azure CLI to modify the size of a Linux VM , you can view a list of the sizes available on the hardware cluster where the VM is hosted using the list-vm-resize-options command, for example: az vm list-vm-resize-options --resource-group testingGroup --name scalingTest --output table You can then use the resize command to change the VM's size to one of the listed options, as shown. This command restarts the VM automatically. az vm resize --resource-group testingGroup --name scalingTest --size Standard_E32d_v4 If the size you want to change the VM to is not available, you can deallocate the VM, which can then be resized to any size supported by the region and restarted; the commands involved are illustrated below: az vm deallocate --resource-group testingGroup --name scalingTest az vm resize --resource-group testingGroup --name scalingTest --size Standard_M128s az vm start --resource-group testingGroup --name scalingTest You can resize a Windows VM on Azure using either the Azure portal or Powershell commands. vSphere To resize a VMware vSphere VM, do the following: Open vSphere Client or Web Client and display the VM inventory. Right-click the VM you want to modify and select Edit Settings. On the Virtual Hardware tab, Expand Memory and change the amount of RAM configured for the VM. Expand CPU and change the number of cores and optionally the number of cores per socket. Make any other desired changes to the hardware resources allocated to the VM. Reconfiguring InterSystems IRIS for Scaled Resources Once you have scaled the host, the next step is to reconfigure InterSystems IRIS to take advantage of the increased resources by changing one or more parameters in the instance's configuration parameter file (CPF). For example, to continue with the common scenario mentioned at the start of this post, now that you have increased the host's memory resources, you will want to take advantage of this by increasing the size of the InterSystems IRIS instance's database cache (which is done by changing the value of the globals parameter) so it can keep more data in memory. An easy way to make such a change, and far the easiest and most repeatable way to make multiple changes to an instance's configuration in one operation or make the same changes to multiple instances, is to use the configuration merge feature, which is available on UNIX® and Linux systems. As described in Using Configuration Merge to Deploy Customized InterSystems IRIS Instances in Running InterSystems Products in Containers and Using the Configuration Merge Feature in the Configuration Parameter File Reference, configuration merge lets you specify a merge file containing the settings you want merged into an instance's CPF immediately prior to a restart. (In release 2021.1 you'll be able to do this on a running instance without restarting it.) Not only is this more convenient than editing an instance's CPF directly, but it is highly repeatable across multiple instances, and supports reliable change management by enabling you to keep an accurate record of changes simply by versioning the configuration merge files you apply. To execute a configuration merge, you need to do the following: Create the merge file with the parameters you want to modify. Stage the merge file in a location accessible to the instance. If the instance you are modifying is in a container (which is likely on a cloud host), you can stage the file in the instance's durable %SYS directory (see Durable %SYS for Persistent Instance Data in Running InterSystems Products in Containers). Specify the merge file's location using the ISC_CPF_MERGE_FILE environment variable before restarting the instance. For example, continuing with the case of the database cache that needs updating, suppose you wanted a containerized instance's database cache size increased to 100 GB. The setting for this, in the [config] section of the CPF, would be globals=102400, which sets the database cache for 8-kilobyte blocks to 102,400 MB, or 100 GB. (As explained in the globals description in the Configuration Parameter File Reference, the parameter sets the size of the cache for multiple block sizes; if only one value is provided, however, it is applied to the 8-kilobyte block size, and 0 [zero] is assumed for the other sizes; globals=102400 is therefore the equivalent of globals=0,0,102400,0,0,0.) To make this change, you might do the following on the cloud host: 1. Create a configuration merge file, called for example mergefile2021.06.30.cpf, containing these lines: [config] globals=102400 2. Stage the merge file in the durable %SYS directory on the host's file system, which if you mounted the external volume /data as /external in the container and used the ISC_DATA_DIRECTORY variable to specify /external/iris_durable as the durable %SYS directory for the instance, would be /data/iris_durable. 3. Use the docker exec command on the host's command line to specify the variable and restart the instance with the iris command; if the instance's container is named iris and the instance is named IRIS, for example, the command would look like this: docker exec iris ISC_CPF_MERGE_FILE=/data/iris_durable/mergefile2021.06.30.cpf iris stop IRIS restart 4. When the instance is restarted, you can confirm the new globals setting with this command: docker exec iris grep globals /data/iris_durable/iris.cpf 💡 This article is considered as InterSystems Data Platform Best Practice.