Call for testers: play with the Code4i FS extension

During the Christmas holidays, between various lunches with relatives, an outing, and, of course, some rest, I had the opportunity to rework the Code4i FS extension a bit. It was very challenging in that it allowed me to learn a new language, TypeScript, and to learn about new aspects and SQL services of the IBM i operating system that I was completely unaware of before.

For those unfamiliar with it, this extension allows you to use and, in some cases, even manage additional objects beyond those traditionally supported by the standard extension. The aim is to improve the user experience for programmers (but not only them) by providing a single interface from which to work and get feedback, avoiding the need to switch frantically between applications. In addition, it is intended as a tool to help those who are just starting out and therefore have less experience, as the GUI greatly simplifies things.

New supported object types are 20, here you can find a list with the major features:

Data Queue

  • Send Message: Keyed/non-keyed support, UTF8 format, length validation, key validation
  • Clear Queue: Removes all messages with confirmation
  • View: Messages (standard & UTF8), queue info, sender details, timestamps

Data Area

  • Change Value: All types (*CHAR, *DEC, *LGL), substring modification (start/length), type-based validation, range checking
  • View: Current value, type, length, decimal positions, text description

Binding Directory

  • Add Entry: *MODULE/*SRVPGM support, *IMMED/*DEFER activation, path validation (library/object format)
  • Remove Entry: Individual entry removal with confirmation
  • View: Entries list, exported procedures from bound service programs

File

  • Query File: Opens SQL editor with pre-filled SELECT statement
  • View: File/table/view/index info, statistics, members, dependent objects, supports PF/LF/VIEW/INDEX

Job Queue

  • Hold/Release/Clear: Queue-level operations with status validation
  • Hold/Release/End Jobs: Individual job management with confirmation
  • View: Queue status, jobs list with details (status, submitter, timestamps)

Journal

  • Generate Receiver: Creates new journal receiver (CHGJRN JRNRCV(*GEN))
  • Display Entries: Opens SQL editor with DISPLAY_JOURNAL table function query
  • View: Journal configuration, receiver chain with statistics, sequence numbers, timestamps

Message Queue

  • Clear Queue: Removes all messages with confirmation (CLRMSGQ)
  • View: Messages with ID, first/second level text, severity, sender job/user, timestamps

Output Queue

  • Hold/Release/Clear: Queue management operations (HLDOUTQ/RLSOUTQ/CLROUTQ)
  • Manage Writer: Auto start/stop based on current state (STRRMTWTR/STRPRTWTR/ENDWTR)
  • Delete Old Spools: Age-based deletion with day input (SYSTOOLS.DELETE_OLD_SPOOLED_FILES)
  • Generate PDF: Download individual spool as PDF (SYSTOOLS.GENERATE_PDF)
  • Delete Spool: Remove individual spooled file (DLTSPLF)
  • View: Queue status, spooled files list with details (name, user, job, pages, size)

Save File

  • Download: Export SAVF to local file (copy to stream file, then download)
  • Upload: Import local file to SAVF (upload, then copy from stream file)
  • Clear: Remove all objects from SAVF (CLRSAVF)
  • Save: Save objects/libraries to SAVF with comprehensive options (SAVOBJ/SAVLIB)
  • Restore: Restore from SAVF with comprehensive options (RSTOBJ/RSTLIB)
  • View: SAVF info, objects list, file members, spooled files, IFS objects (multi-panel)

Subsystem

  • Start: Start subsystem with confirmation (STRSBS)
  • End: End subsystem with option selection *IMMED/*CNTRLD (ENDSBS)
  • End Jobs: End individual jobs in subsystem (ENDJOB)
  • View: Subsystem status, pools, autostart jobs, workstation entries, routing entries, prestart jobs, job queue entries, active jobs

User Space

  • Change Value: Modify user space data with start position and value input (QSYS2.CHANGE_USER_SPACE)
  • View: Size, extendable flag, initial value, domain, data (text and binary/hex)

Class (Read-Only)

  • View: Run priority, time slice, resource limits (CPU time, temporary storage, threads), default wait time, purge eligibility, usage statistics
  • Note: Uses QWCRCLSI API via SQL stored procedure (auto-created on first use)

Command (Read-Only)

  • View: Processing program, validity checking program, prompt override program, message/help files, execution environment settings (interactive/batch/REXX), threading attributes, CCSID

DDM File (Read-Only)

  • View: Remote location info (system name/address, port), access method, remote file name/library, connection settings
  • Note: Parses DSPDDMF output, handles multi-line field values

Job Description (Read-Only)

  • View: Job queue, output queue, library list, accounting code, routing data, message logging, job switches, hold on job queue

Journal Receiver (Read-Only)

  • View: Status, size, sequence numbers (first/last), attach/detach/save timestamps, linked receivers (previous/next), remote journal configuration, filter settings

Message File (Read-Only)

  • View: All messages with ID, first/second level text, severity, reply type, default reply, valid reply values/ranges

Module (Read-Only)

  • View: Basic info (creation date, source file, compiler options), size details (code, debug data, static storage), procedures list, imports/exports, referenced system objects, copyright strings
  • Note: Uses DSPMOD with multiple DETAIL options (*BASIC, *SIZE, *IMPORT, *EXPORT, *PROCLIST, *REFSYSOBJ, *COPYRIGHT)

Program/Service Program (Read-Only)

  • View: Program info, bound modules with source details, bound service programs with signatures, exported procedures (SRVPGM only), SQL settings, optimization details, activation group

Query Definition

  • Translate to SQL: Converts Query/400 definitions to SQL format using RTVQMQRY command
  • View: SQL translation of query definition with proper table notation (LIB.FILE instead of LIB/FILE)
  • Note: Uses temporary source file and alias for extraction, automatically cleans up temporary objects

I would like to point out that this is not the final version; it is currently being reviewed by the Code4i team as the extension is part of that ecosystem. It is therefore possible that it may undergo further changes.
However, it would be interesting for other users to be able to test it now in ALPHA so that any bugs can be checked and corrected, as well as to gather feedback on new features. So, if you want to be a tester, write a comment and I’ll get back to you with instructions.

Andrea

Monitoring SSL certificates with SQL

System security is becoming one of the most important issues that IT managers have to deal with. This also applies to IBM i systems. In fact, the days when the only access to systems was via a terminal are long gone. Now systems are at the center of complex ecosystems that communicate with each other in various ways (REST APIs, remote commands, database queries, etc.).

One of the enabling factors for establishing secure communication is undoubtedly the use of SSL/TLS certificates. In a previous post, we saw how to download and import them using DCM or the tools provided by the QMGTOOLS library. For those who don’t know, internet standardization bodies have decided to gradually (but at the same time drastically) reduce the duration of these certificates. Consider that today the standard is about one year for the duration of SSL certificates, while in 2029 the target is to make them last ONLY 47 days…

As you can imagine, if a service uses these certificates and they expire in the meantime, this causes a blockage of services and, consequently, of the business connected to them. This is why it is essential to have a monitoring system that, beyond the expiration date, also provides visibility of the applications affected by the certificate change…

First, let’s extract the list of certificates with private keys (those for server or client applications that require authentication):

SELECT CERTIFICATE_LABEL, VALIDITY_START, VALIDITY_END FROM TABLE (QSYS2.CERTIFICATE_INFO(CERTIFICATE_STORE_PASSWORD => 'XXXXX')) WHERE private_key = 'YES'

In this way you can also put a where condition on the days between current date and expiration date:

SELECT CERTIFICATE_LABEL, VALIDITY_START, VALIDITY_END, TO_CHAR(TIMESTAMPDIFF(16, CHAR(VALIDITY_END – CURRENT_TIMESTAMP))) AS DAYS_REMAINING FROM TABLE (QSYS2.CERTIFICATE_INFO(CERTIFICATE_STORE_PASSWORD =>’XXXXX’)) WHERE PRIVATE_KEY = ‘YES’ ORDER BY VALIDITY_END;

With this query you are able to extract every system service that is using SSL/TLS:

SELECT DESCRIPTION, APPLICATION_ID, APPLICATION_TYPE, CERTIFICATE_STORE, CERTIFICATE_LABELS FROM QSYS2.CERTIFICATE_USAGE_INFO WHERE CERTIFICATE_STORE = '*SYSTEM' AND CERTIFICATE_LABEL_COUNT > 0

Now let’s print the applications and associated certificates:

SELECT DESCRIPTION, APPLICATION_ID, APPLICATION_TYPE, CERTIFICATE_STORE, CERTIFICATE_LABELS, CERTIFICATE_LABEL, VALIDITY_START, VALIDITY_END FROM QSYS2.CERTIFICATE_USAGE_INFO X INNER JOIN TABLE (QSYS2.CERTIFICATE_INFO(CERTIFICATE_STORE_PASSWORD => 'XXXXXX')) Y ON X.CERTIFICATE_LABELS LIKE '%' CONCAT Y.CERTIFICATE_LABEL CONCAT '%'  WHERE CERTIFICATE_STORE = '*SYSTEM' AND CERTIFICATE_LABEL_COUNT > 0

And you, do you have any service with SSL enabled and a real certificate monitoring tool?

Andrea

Let’s try bob – part 1

This week, the wait is finally over… a few weeks after signing up for the demo, BOB has finally arrived, and I have the chance to try it out in advance.

For those who are not yet familiar with it, BOB is a new IDE owned by IBM. It is not a completely new IDE; in fact, for those who regularly use Visual Studio Code, the environment will be very familiar, because BOB is based on it. The reasons for this choice are quite simple to identify. First, compared to RDi, Visual Studio Code is much lighter and more performant, as well as being significantly more modular. Second, Visual Studio Code is a standard IDE, convenient for any programming language. In fact, there are extensions for virtually any language, which makes development on IBM i much closer to industry standards.

Now, if BOB were just a copy-and-paste version of VSCode, it would be useless… The real added value of BOB is its native integration with artificial intelligence. In fact, when you open it for the first time, you immediately notice the prompt for interacting with the agent. In this case, compared to other competitors, the artificial intelligence offered here is based on the aggregation of several models, so you have a complete stack that allows you to respond to very different needs. Moreover, as you can imagine, since BOB is from IBM, it is well-trained in all IBM languages, such as RPG.

I’ll start today by attaching the link to BOB’s YouTube channel, where you can see BOB at work on some use cases tested directly by IBM: https://www.youtube.com/channel/UC-dkbPjzN2bh-k-V4rZQppQ

Now, let’s talk about my experience… as soon as it arrived, I put it to work on one of my Java projects. It’s actually the backend of an HTTP portal that we use to provide services to our customers. First, I asked it to generate some documentation (yes, I don’t like writing documentation), and in about an hour, it wrote all the javadoc for over 140 classes. In addition to writing the documentation, I was pleased to note that it is able to suggest possible improvements to the code. In this case, for example, it highlighted the possibility of SQL injection:

This is just an example; it also suggests possible code refactoring.

Now, let’s talk about evaluations… We are only at the beginning, and I haven’t been able to test it sufficiently yet, but let’s say that expectations are very high. As for the documentation I asked him to write for me, it seems to be very focused on the subject… I still have some doubts about code generation, but I also believe that it should definitely be an aid (and it is) to the programmer, not a replacement. Another definitely positive thing is that it asks for permission before accessing/modifying a file, showing all the changes in a preview and explaining them. On the other hand, the demo comes with a $20 budget, and I’ve already burned through about $14 just with the documentation I asked for, which means I can’t really test it thoroughly.

From my point of view, the next steps concern the RPG world, i.e., the automatic generation of test cases and code documentation. This is because, in addition to the IDE, it is also possible to invoke BOB’s APIs from the CLI, meaning it can be integrated into automatic compilation/release pipelines.

For completeness, I am attaching the link to sign up for the BOB demo in case you haven’t already done so: https://www.ibm.com/products/bob

Have you had the opportunity to test and use artificial intelligence tools in your work? What do you think?

Andrea

Using SQL to change BRMS media

It is quite common to have customers with specific backup requirements, such as changing the expiration date of the tape used based on the day of the month or year for tax purposes. For this reason, it is always complicated to have standard jobs or calendars with a predefined retention period.

So if a standard approach is not feasible, we go for a custom approach… Now SQL and BRMS come to our aid. In fact, there are several SQL services compatible with 5770BR1, and even more with 5770BR2.

Now, let’s proceed with creating an SQL procedure that modifies the media class, move policy, and retention for the tapes used in the job in which it is launched. Then, let’s extract the queries we need:

  1. Find the current job: select job_name from TABLE (QSYS2.ACTIVE_JOB_INFO(DETAILED_INFO => 'NONE', JOB_NAME_FILTER => '*'))
  2. Find tapes and creation date: select volume_Serial, created from qusrbrm.media_info
  3. Find job that changes a tape: select tmcvsr, TRIM(LPAD(TMJNBR, 6, '0') CONCAT '/' CONCAT TRIM(TMUSER) CONCAT '/' CONCAT TRIM(TMCJOB)) from qusrbrm.qa1amm

Now, let’s create a query that give us serial number and the new expiration date: SELECT VOLUME_SERIAL, CASE WHEN RETENTION <> 9999 THEN TO_CHAR(CREATED + RETENTION DAYS, 'ddMMyy') ELSE 'PERM' END FROM QUSRBRM.MEDIA_INFO INNER JOIN QUSRBRM.QA1AMM ON VOLUME_SERIAL = TMCVSR INNER JOIN TABLE (QSYS2.ACTIVE_JOB_INFO(DETAILED_INFO => 'NONE', JOB_NAME_FILTER => '')) ON TRIM(JOB_NAME) = TRIM(LPAD(TMJNBR, 6, '0') CONCAT '/' CONCAT TRIM(TMUSER) CONCAT '/' CONCAT TRIM(TMCJOB))

So, in our case, we have RETENTION that is a variable that contains the number of days to maintain the tape active, 9999 is a special value that in my case means that the tape should not have an expiration date.

At this point, it’s all very easy. I just have to loop through the result set and run the CHGMEDBRM command with the correct parameters for media class, move policy, and retention.

As usual, you can find the source code for the procedure, download it, and edit it as you wish.

Andrea

Remote tables: a bridge between 2 IBM i

I often find myself in a situation where I have several different systems and need to extract data from all of them by running queries from a single partition. Well, there is a DB2 for i function that allows you to run SELECT SQL on remote machines.

What do we need? First of all, it is essential that the database of ‘remote’ machines be registered in the central system’s database address book. To verify that this is the case, use the command WRKRDBDIRE and, if necessary, add 1 (or use the command ADDRDBDIRE):

In my example, I am working on the ELM760 machine and trying to connect to the ELM750 machine.

Traditionally, it was already possible to connect from one database to another using the CONNECT TO remote database name statement, but in this case, you opened a stable connection that was closed only when the SQL job was closed or, in general, with the CONNECT RESET statement:

There is another, more convenient way, which is to use REMOTE TABLES. In fact, it is possible to query tables from another system in a single statement. Let’s look at an example:

As you can see, connected to ELM760, I am simply interrogating ELM750. This also works for table functions:

Now, in order for everything to work correctly, it is necessary to define entries at the GO CMDAUTE authentication information level. In this case, it is possible to set up specific authentication for each target lpar or (although I do not recommend this for security reasons) generic authentication for the QDDMDRDASERVER server (clearly only applicable to the user to whom the authentication applies).

The only structural limitation is the inability to join objects from two different databases, so for example I cannot join (or merge) objects that come from the local database and the remote database:

And you, have you ever tried remote tables in IBM i?

Andrea