Dmitry Maslennikov · Dec 10, 2020 go to post

Those tools already have some expertise in that area. Yeah, they may have some difficulties with InterSystems IRIS, may not understand some of the features of InterSystems SQL language, and so on. DBeaver, for instance, is an open-source project and can be improved by anybody. 

But I'm not sure that it's a good idea to invest so much time in implementing something, which already available and in some cases for free.

Having too many tools out of the box, not so good idea, it will not mean that all of those tools will have enough quality. 

So, in this case, I would focus development on improving existing tools, in better support for InterSystems products. It will take less time, with a bigger profit (at least InterSystems will be noticeable not only for current InterSystems users).

Dmitry Maslennikov · Dec 10, 2020 go to post

Why it has to be implemented inside? Why would not use some already well-established tools, such as DBeaver, JetBrains DataGrip, and so on?

First of all, it's not a common case for any code editor, and for sure VSCode is not an exception. What are you talking about is kind of deployment process. And have to be solved in that manner. You have to produce some kind of version of your application and install it. It's how it's supposed to be.

At the moment with VSCode, you can export any source code from the server, to get all the classes locally. And import those files as a folder. But it may not work as you would expect, and may cause some compiling issues. This case will not be changed in the future, as completely make no sense to have in the Editor.

The issue not in Caché, it’s in Windows, which just not allows any interaction from services. You can enable it by editing service.

But in your case I would look into other ways for interaction. Server means, that in 99% of time it works alone with no people sitting behind the screen, even it should not have a screen at all. So, in normal case it’s very small chance that anybody will see your message and press ok.

If you need a suggestion on how would it better, please describe what’s exactly you are trying to achieve.

I am not sure about something simple out of the box. I would go with creation some class for particular XML schema, which will extend %XML.Adaptor, so, will be able to be imported from XML. And extended by %JSON.Adaptor, so, it will be possible to export it to JSON. And vice-versa.

Unfortunately, docker-compose does not have any way, on how to limit cpus during build. While it's possible for deploy. The only way to do it in your case, is to build image manually with specified limitation.

docker build -t someimagename --cpuset-cpus 0 .

and then just add this image name to docker-compose.yml, you can keep the build section, it will not be used if you desired image already produced.

services:
  iris:
    image: someimagename
    cpuset: "0-7"

You can omit schema in the query of your scheme is set as default, by default it’s SQLUser for class package User. You are also able to change sql name for a package. In case that default sqlname is quite long you are able to make it shorter.

Whan, you work through SQL empty string as $Char(0) in storage, while NULL as an empty string.

So, I would suggest you update it will NULL value. 

What about your JSON, I'm not sure how you get it. If you using %JSON.Adaptor, you can set parameter %JSONNULL  to 1 for class, or for a particular property, so, it will not exclude it from export.

Dmitry Maslennikov · Nov 27, 2020 go to post

For any new project based on IRIS, I would recommend, to have all the application logic outside of InterSystems IRIS, and use it only as a database. For instance with NodeJS Native API

Dmitry Maslennikov · Nov 26, 2020 go to post

But the issue may be in Raspbian, which I suppose is 32 bit, while 64 bit yet in beta. And you have to install 64 bit version of Raspbian or Ubuntu 20.04 64 bit

Dmitry Maslennikov · Nov 26, 2020 go to post

RPi 4 should be fine, it's just the first edition which got 64 bit, RPi 3 was 32 bit and it would not run IRIS anyway.

Dmitry Maslennikov · Nov 26, 2020 go to post
$ docker run --init --name my-iris -it --rm -p 9091:1972 -p 9092:52772 -p 9093:52773 -p 9094:7041 store/intersystems/iris-community-arm64:2020.4.0.524.0                                                                              

[INFO] Starting InterSystems IRIS instance IRIS...
[INFO] This copy of InterSystems IRIS has been licensed for use exclusively by:
InterSystems IRIS Community
Copyright (c) 1986-2020 by InterSystems Corporation
Any other use is a violation of your license agreement
Starting IRIS 

Sign-on inhibited.
See messages.log for details. 

[ERROR] Unknown QEMU_IFLA_INFO_KIND ipip
Unknown QEMU_IFLA_INFO_KIND ip6tnl
qemu: uncaught target signal 6 (Aborted) - core dumped
11/26/20-10:05:11:295 (954) 0 [Generic.Event] Global buffer setting requires attention.  Auto-selected 25% of total memory.
11/26/20-10:05:11:508 (954) 0 [Generic.Event] Allocated 1557MB shared memory: 1234MB global buffers, 123MB routine buffers
11/26/20-10:05:12:118 (954) 0 [WriteDaemon.UsingWIJFile] Using WIJ file: /usr/irissys/mgr/IRIS.WIJ
11/26/20-10:05:12:119 (954) 0 [WriteDaemon.CreatingNewWIJ] Creating a new WIJ file
11/26/20-10:05:13:081 (954) 0 [WriteDaemon.CreatedNewWIJ] New WIJ file created
11/26/20-10:05:13:205 (957) 0 [WriteDaemon.Started] Write daemon started.
11/26/20-10:05:13:206 (957) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38
11/26/20-10:05:13:222 (964) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38
11/26/20-10:05:13:222 (963) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38
11/26/20-10:05:13:224 (957) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38...(repeated 63 times)
11/26/20-10:05:13:224 (957) 1 [Generic.Event] Write daemon asynchronous I/O disabled dueto failure allocating control structures.
11/26/20-10:05:13:228 (964) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38...(repeated 63 times)
11/26/20-10:05:13:228 (964) 1 [Generic.Event] Write daemon asynchronous I/O disabled dueto failure allocating control structures.
11/26/20-10:05:13:228 (963) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38...(repeated 63 times)
11/26/20-10:05:13:228 (963) 1 [Generic.Event] Write daemon asynchronous I/O disabled dueto failure allocating control structures.
11/26/20-10:05:15:881 (954) 0 [Generic.Event]
Startup of InterSystems IRIS [IRIS for UNIX (Ubuntu Server LTS for ARM64 Containers) 2020.4 (Build 524U) Thu Oct 22 2020 16:49:47 UTC]
    in ./
    with mgr: /usr/irissys/mgr
    with wij: /usr/irissys/mgr/IRIS.WIJ
    from: /usr/irissys/mgr/
  OS=[Linux], version=[#1 SMP Fri May 8 23:03:06 UTC 2020], release=[5.4.39-linuxkit], machine=[aarch64]
  nodename=[dbac38c4a18e].
  numasyncwijbuf: 0, swdwrtmax: 0, wijdirectio: on, synctype: 3
  System Initialized.
11/26/20-10:05:17:582 (979) 0 [Database.MountedRW] Mounted database /usr/irissys/mgr/ (SFN 0) read-write.
11/26/20-10:05:18:285 (979) 3 [Generic.Event] Process 979 (JobType=Interactive job (application mode),Dumpstyle=0,Directory='/usr/irissys/mgr/') caught signal 11.
11/26/20-10:05:18:793 (979) 3 [Generic.Event] If core dumps are enabled, a core file will be created by process 982 in the location specified by the system configuration.
11/26/20-10:05:18:802 (979) 3 [Generic.Event] Parent process will clean up and halt
[ERROR] See /usr/irissys/mgr/messages.log for more information
[FATAL] Error starting InterSystems IRIS
Dmitry Maslennikov · Nov 26, 2020 go to post

Could you provide what error you got?

I've tried to run it with Qemu, on GitHub Actions, or locally on macOS (Docker on macOS supports running ARM64 images as well)

I don't have RPi, yet. Did not manage to play with it, but at least I've managed to run it on AWS EC2 ARM64 instance.

My messages.log when failed was looked like this.

Dmitry Maslennikov, [16.11.20 13:29]
11/16/20-09:09:14:181 (957) 0 [Generic.Event] Global buffer setting requires attention.  Auto-selected 25% of total memory.
11/16/20-09:09:14:302 (957) 0 [Generic.Event] Allocated 1557MB shared memory: 1234MB global buffers, 123MB routine buffers
11/16/20-09:09:14:396 (957) 0 [WriteDaemon.UsingWIJFile] Using WIJ file: /usr/irissys/mgr/IRIS.WIJ
11/16/20-09:09:14:398 (957) 0 [WriteDaemon.CreatingNewWIJ] Creating a new WIJ file
11/16/20-09:09:14:862 (957) 0 [WriteDaemon.CreatedNewWIJ] New WIJ file created
11/16/20-09:09:14:897 (957) 0 [Generic.Event] 
Startup of InterSystems IRIS [IRIS for UNIX (Ubuntu Server LTS for ARM64 Containers) 2020.4 (Build 524U) Thu Oct 22 2020 16:49:47 UTC]
       in ./
       with mgr: /usr/irissys/mgr
       with wij: /usr/irissys/mgr/IRIS.WIJ
       from: /usr/irissys/mgr/
  OS=[Linux], version=[#1 SMP Fri May 8 23:03:06 UTC 2020], release=[5.4.39-linuxkit], machine=[aarch64]
  nodename=[buildkitsandbox].
  numasyncwijbuf: 8, swdwrtmax: 64, wijdirectio: on, synctype: 3
  System Initialized.
11/16/20-09:09:14:933 (972) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38
11/16/20-09:09:14:936 (966) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38
11/16/20-09:09:14:937 (972) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38...(repeated 63 times)
11/16/20-09:09:14:937 (972) 1 [Generic.Event] Write daemon asynchronous I/O disabled dueto failure allocating control structures.
11/16/20-09:09:14:940 (966) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38...(repeated 63 times)
11/16/20-09:09:14:940 (966) 1 [Generic.Event] Write daemon asynchronous I/O disabled dueto failure allocating control structures.
11/16/20-09:09:14:947 (960) 0 [WriteDaemon.Started] Write daemon started.
11/16/20-09:09:14:948 (960) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38
11/16/20-09:09:14:949 (960) 2 [Generic.Event] create_iotd_pool failed because LKIO_SETUP returned error 38...(repeated 7 times)
11/16/20-09:09:14:949 (960) 1 [Generic.Event] Write daemon asynchronous I/O disabled dueto failure allocating control structures.
11/16/20-09:09:15:354 (982) 0 [Database.MountedRW] Mounted database /usr/irissys/mgr/ (SFN 0) read-write.
11/16/20-09:09:15:397 (982) 3 [Generic.Event] Process 982 (JobType=Interactive job (application mode),Dumpstyle=0,Directory='/usr/irissys/mgr/') caught signal 11. 
11/16/20-09:09:15:404 (982) 3 [Generic.Event] Parent process will clean up and halt
11/16/20-09:09:15:405 (982) 3 [Generic.Event] If core dumps are enabled, a core file will be created by process 985 in the location specified by the system configuration.
Dmitry Maslennikov · Nov 24, 2020 go to post

Official online documentation for IRIS, available only online or offline as PDF only.

Class Reference Documatic, working only when the server is up and running. 

No static HTML documentation at all.

Dmitry Maslennikov · Nov 24, 2020 go to post

The applications you mentioned, it's not exactly applications, it's just kind of entrypoint to the application.

Security in Caché and in IRIS now, was not so good in my opinion, for many reasons.

An application developer, if he would like to use role-based security is too limited to use the Security model from InterSystems.

And no matter how many different applications customers would like to use on their own Instance of IRIS, security will be global.

Issues with mirroring, with ECP, any instance of IRIS use own tables, and have to be synchronized in some ways. Such big clusters should have the ability to use the same security settings on any instance, out of the box.

Application, real, not virtual, should have the ability to re-use Security and store it close to Application's data.

Dmitry Maslennikov · Nov 23, 2020 go to post

You have to use HTTPS, for such tasks, encryption passwords on the client-side not secure in any way. The only way to make it secure is by using SSL. Base64 is far from Security, anybody with such a string can get a real password. With SSL, it will be impossible to decrypt any traffic between client and server. So, even way, to catch anything about a password.

Dmitry Maslennikov · Nov 20, 2020 go to post

You should understand that there are no reasons, to implement something, which can be done better with external solutions. On Linux InterSystems does not have even telnet, for the same reasons. I'm against implementing it directly in Caché/IRIS.

Back to your the next issue. You have to understand that ssh connection should use authentication, and for sure it should be done on InterSystems side, it's should be done on SSH level. And I see only one way, how to implement it, is using Kerberos. I would suggest that, if you have Windows in your park machine, you may have Active Directory, so, Singe Sign On with Active Directory, looks the best way (it's even possible with Linux). Your users in Caché, should be tied with Active Directory accounts. Target Windows server and Caché should be configured for Kerberos authentication, as well as SSH server. In this case, any user already signed on on their machine with Active Directory account, may get fast connection to the system on Caché through SSH, without any prompt for login/password. Using the right SSH client, which will support Kerberos.

It does not matter if you even used Linux, and had to solve the same task, the solution would be exactly the same.

Dmitry Maslennikov · Nov 19, 2020 go to post

Well, I have not used Admin SDK in google, yet. And it was the first time, for me. But I've managed to get JWT and AccessToken, and was able to make requests. Unfortunately, configuration on the IRIS side is very tricky.

OAuth2 Client server should be filled manually

Issuer endpoint: https://oauth2.googleapis.com/token

This issuer is important

SSL configuration: created manually, only fill the name

And two required endpoints

https://accounts.google.com/o/oauth2/v2/auth

https://oauth2.googleapis.com/token

I did not use JSON file with private key here. But I've used it for X509

I did not manage to get it worked without configured X509. 

URL from `client_x509_cert_url` field in JSON provided by Google, opened it in browser, It contains three certificates in JSON. Took the latest one. Saved in file, replaced \n with end lines.

and `private_key` from file, saved as google.key. 

When press save, it compares certificate and private key if the match, it will be saved.

Back to OAuth2, create client configurations. First of all, go to JWT settings, fill just created X509.  And Request Algorithms.

On the Client Credentials, tab fill Client ID with value of `client_email` from JSON.

Back to General, tab, fill Application name, SSL configuration. Client Type as Resource server, ( by unknown reasons will hide Request algorithms group of fields on JWT tab).

And that's it. Code to create JWT

  Set p("scope") = "https://www.googleapis.com/auth/admin.directory.user"

  Set p("exp") =  ##class(%OAuth2.Utils).TimeInSeconds($ZTimestamp, 3600)
  Set p("iat") = ##class(%OAuth2.Utils).TimeInSeconds($ZTimestamp)

  Set jwt = ##class(%SYS.OAuth2.Request).MakeRequestJWT("google", .p, .tSC)
  If $$$ISERR(tSC) {
    Do $System.OBJ.DisplayError(tSC) 
    Quit
  }
  
  Write !,"JWT:",!,jwt

It Should be quite long, and have three groups, separated by dots, if it ends with a dot, means it did not find how to sign it. Check the settings.

And request access token

  Set hs = ##class(%Net.HttpRequest).%New()
 
  Do hs.InsertFormData("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
  Do hs.InsertFormData("assertion", jwt)   

  Set hs.Https = 1
  Set hs.SSLConfiguration = "google"
 
  Set tSC = hs.Post("https://oauth2.googleapis.com/token")
  If $$$ISERR(tSC) {
    Do $System.OBJ.DisplayError(tSC)
    Quit
  }
  Set response = {}.%FromJSON(hs.HttpResponse.Data)
  Set accessToken = response."access_token"
 
  Write !!,"AccessToken:",!,accessToken

And finally you can use that access token in the header Authorization, with prefix Bearer

  Set hs = ##class(%Net.HttpRequest).%New()
  Do hs.SetHeader("Authorization", "Bearer " _ accessToken)
 
  Set hs.Https = 1
  Set hs.SSLConfiguration = "google"
 
  Set tSC = hs.Post("https://www.googleapis.com/admin/directory/v1/users")
  If $$$ISERR(tSC) {
    Do $System.OBJ.DisplayError(tSC)
    Quit
  }
  Set response = {}.%FromJSON(hs.HttpResponse.Data)
Dmitry Maslennikov · Nov 19, 2020 go to post

VSCode, while configured to work with docker, have a short action to open terminal, through menu on connection status

Dmitry Maslennikov · Nov 19, 2020 go to post

Configuring SSH to connect to Caché, on Windows will be almost the same as doing it on Linux.

You have to install any SSH server, for instance, OpenSSH.

And then configure there default shell, to be something like this

c:\intersystems\cache\bin\cache.exe  -s c:\intersystems\cache\mgr

or for iris, use irisdb.exe, instead

c:\intersystems\iris\bin\irisdb.exe  -s c:\intersystems\iris\mgr

but it looks, that to change default shell in openSSH, you have to edit the registry.