An API to simplify retrieval of Zowe Profile Information

Gene Johnston
Zowe
Published in
10 min readMay 12, 2021

Co-authored with Timothy Johnson

Your Zowe profile gets yo where you need to go
Your Zowe profile points you in the right direction

{Core} This article describes the purpose and use of a new API that can be used to more easily retrieve The Open Mainframe Project’s Zowe profile property values.

Background on Zowe client profiles

A Zowe client runs on a system that is remote from a z/OS mainframe. A Zowe client profile is a means to specify properties associated with a particular app or component. Typically, the component is a REST service on a z/OS system. Profile properties include the connection information needed to communicate with the desired service on the correct LPAR. Host and port are always required. A user and password are also needed to ensure that the user is authorized to use the service (we will ignore tokens in this discussion).

In addition to connection-related properties, other properties may be needed for a particular service to perform a desired action. Examples include a data set name, a job name, a region name, etc.

For the Zowe command-line app (zowe-cli), these properties are equivalent to command-line arguments. When a large number of arguments are repeatedly specified for a number of sequential CLI commands , the repetitive typing becomes tedious and error prone. A profile is a means to permanently store frequently used properties on disk, thus reducing how much information must be specified on any given command. If a CLI command or plugin defines its profile to include a given property, a value for that property can be stored on disk and automatically retrieved by the command, instead of requiring the user to specify such values on every command.

Profiles affect more than just CLI commands

GUI client apps can also be built upon Zowe CLI’s Imperative framework. In particular, the Imperative package provides many common functions that can be used by both CLI and GUI apps. Currently, most GUI apps built upon the Zowe CLI framework are Visual Studio Code extensions. Zowe Explorer is one such app, but a growing number of REST service developers are also creating VS Code extensions specific to their REST application.

Such apps do not have command line arguments, but they have the same need for connection-related properties and app-related properties. If such properties are not readily available, the app must prompt the user for such values before performing the desired operation. This can be even more annoying for a GUI user than the typing of repetitive arguments are to a command-line user. To avoid such difficulties, profiles perform the same service for these GUI apps as they do for CLI apps.

Profiles evolve with new team configuration

In a future release of Zowe CLI, we intend to deliver a new type of Zowe configuration file, which is referred to as a “team configuration”. At the publication date of this article, our team configuration enhancement was available for experimentation by early adopters through the @next versions of @zowe/cli and @zowe/imperative. A detailed description of our team configuration is beyond the scope of this article. You can read an introduction to team configuration in the article titled “Zowe CLI — Getting Started, Made Easy!”.

Team configuration affects the use of profiles in the way that profile information is stored. Profiles are no longer stored in separate files, within separate sub-directories. The profiles for all components are consolidated within one configuration file.

Side note: There is potentially more than one configuration file, but either it is used in a specific directory (or contains user overrides in the same format). Again, these variations are beyond the scope of this article. For our purposes, we can think of the profiles for all services as residing in one configuration file.

Another structural change of the team configuration is that a user can nest various levels of properties, which enable a profile at one level of nesting to inherit properties from a higher level of nesting within the configuration. The purpose of such nesting is to enable a user to share a repetitive property (like host name) among numerous profiles.

Even with these structural changes, the purpose and properties of a given profile remains the same. Thus, the concern of an app developer, and the focus of this article is: “how do I extract my relevant profile information given the structural changes with the new team configuration?”.

A new ProfileInfo API

Some previous API functions were originally created for use in the Zowe CLI. At times those APIs relied on functions that are automatically performed for CLI commands and data that is automatically provided to CLI command handlers. GUI apps, like VS Code extensions, could not take full advantage of these older APIs. As a result, the VS Code extensions implemented their own similar solutions to meet their needs. With a growing number of VS Code extensions, those custom implementations diverged, resulting in a customer experience that varied from one GUI app to another.

Because a CLI command does one operation and it is done, it has a different dynamic than a GUI app. When a different profile type is required, or a different default profile of a given type is needed, a CLI user just specifies that override value on a given command (or runs a couple of commands in sequence). A GUI app may want to provide the user with a list of choices from which to select, and then take all of its actions in that mode until the user makes a switch. Therefore, GUI apps need some additional queries beyond what is needed by a CLI app.

The ProfileInfo API is a new class within the Imperative package. This API is intended to specifically improve access to information from Zowe profiles to apps (like GUI apps) that do not rely directly upon Zowe command-line actions.

Features of the ProfileInfo API include:

  • Read a Zowe configuration from disk.
  • Transparently read either a new team configuration or old style profiles.
  • Enable the reading of profile information from disk to be re-triggered at the app’s discretion.
  • Provide a list of all typed profiles.
  • Provide an option to list only profiles of a specific type.
  • Resolve nested inheritance of profile property values.
  • Resolve values specified in both service profiles and base profiles.
  • Resolve overrides of property values specified in a user configuration file.
  • Provide information to enable callers to prompt for missing, but required profile properties.

Which apps should use the ProfileInfo API ?

As implied by my previous statements, Zowe-based VS Code extensions should be the prime beneficiaries of the ProfileInfo API. If you are writing a GUI app that is not a VS Code extension, but is using the Zowe Imperative framework and profiles, your work should also be simplified by using the ProfileInfo API. If you are writing a GUI app that is not a VS Code extension, let us know about it. We would be delighted to hear about the types of things that you are accomplishing with the Imperative framework.

If you are a Zowe-CLI plugin developer, you may be wondering if you need to devote effort to programming with this new API. The answer is no. The ProfileInfo API will not provide benefits to your plugin. The good news is that you do not need it. For close to a year, the Imperative framework has been automatically resolving argument values through our order of precedence before the complete set of command-line arguments are passed into your command handler through its params:IHandlerParameters argument. Further, as part of our recent implementation of team configuration, we modified the Imperative framework to automatically read a team configuration (if it exists) and automatically fall back to old style profiles if a team configuration does not exist. This means that any @next version of a CLI command will automatically work with a new team configuration, and it will be backward compatible at any customer site which chooses to use old style profiles for a period of time before transitioning to team configuration.

There really is no need for CLI plugins to directly access profiles. Any profile values will be automatically included in the params:IHandlerParameters argument of the command handler. If a plugin contains any code to directly access profiles, that code should be removed or replaced, because those operations will not work with a team configuration. Code snippets to search for include:

  • class CommandProfiles
  • params.profiles.get(…)
  • params.profiles.getMeta(…)

For the best, most consistent user experience, a plugin should adhere to the Zowe conformance guidelines. If your plugin adheres to the conformance guidelines, automatic support of team configuration and automatic fall-back to old-style profiles should be transparent to the plugin.

Where do I find details about the ProfileInfo API ?

  • Background information on the design of the ProfileInfo API is available in this Github issue: Design Proposal for Zowe Profile Information API
  • The @next version of the Zowe-CLI SDK documentation is available on the Zowe Jenkins server at: Zowe Node.js SDK
  • The Zowe-CLI SDK documentation page specific to the ProfileInfo class is: Class ProfileInfo
  • The ProfileInfo API is currently available for experimentation through the NPM tag: @zowe/imperative@next
  • A version of the Zowe-CLI which uses the @next version of imperative is available through the NPM tag: @zowe/cli@next

The flow of operations with the ProfileInfo API

Previously, the process to load profile information could be quite complex, especially when loading secure credentials. The process went something like this:

  1. Check if a CredentialManager like the Secure Credential Store for Zowe CLI is enabled in ~/.zowe/imperative/settings.json
  2. If so, initialize CredentialManagerFactory and override some of its methods.
  3. Initialize a profile manager to load profile properties from a service profile (e.g., z/OSMF, CICS)
  4. If profile properties are missing, try to load them from a base profile.
  5. If profile properties are still missing, prompt the user to enter values.

Using the new ProfileInfo API, this process is much simpler. A single class contains all the methods needed to load profiles and handles most of the “dirty work” for you.

The following code snippets demonstrate various operations within the ProfileInfo API, including how secure credentials can be retrieved.

First, the ProfileInfo class must be initialized to have access to its methods. Only one argument is required to initialize the class, which is the name of the application whose profiles you’re loading, in this case “zowe”.

const profInfo = new ProfileInfo("zowe");

Second, we read the profiles from disk and cache them in memory. This method must be awaited because it performs disk I/O. The ProfileInfo API supports loading either team configuration profiles or old style profiles. If zowe.config.json is found at the project or global level, then only team config profiles are loaded. Otherwise, old style profiles are loaded from the ~/.zowe/profiles directory, which ensures backwards compatibility for users who haven’t created team configuration profiles.

await profInfo.readProfilesFromDisk();

Next, we retrieve information about the default z/OSMF profile. If none exists, then null is returned. If a default z/OSMF profile does exist, then an object is returned that contains the profile’s attributes, like the following:

const zosmfProfile = profInfo.getDefaultProfile("zosmf");{
"profName": "lpar1.zosmf",
"profType": "zosmf",
"isDefaultProfile": true,
"profLoc": {
"locType": ProfLocType.TEAM_CONFIG,
"osLoc": "~/.zowe/zowe.config.json",
"jsonLoc": "profiles.lpar1.profiles.zosmf"
}
}

This object can be passed back to the ProfileInfoAPI to uniquely identify the profile whose properties should be loaded.

If we want to retrieve a list of all z/OSMF profiles and their attributes from which we allow a user to select, we could do this instead:

const profAttrs = profInfo.getAllProfiles("zosmf");

Finally, we are able to merge arguments for a profile by automatically loading them from multiple sources.

const zosmfArgs = profInfo.mergeArgsForProfile(zosmfProfile);

Arguments are merged in the following order of priority:

  1. Service profiles like the z/OSMF profile whose attributes are shown in the example above.
  2. Base profiles which define properties for multiple types of services
  3. (optional) Environment variables — This behavior is disabled by default, but you can opt in to load arguments from environment variables like the Zowe CLI does (e.g., ZOWE_OPT_PORT for port number of a service).

If the previous step had returned null, there would be no service profile to load, but in that case we could skip over service profiles and still load arguments based on the profile type. Many of those arguments may be missing, but that is also useful information to the app, as we will see later.

const zosmfArgs = profInfo.mergeArgsForProfileType("zosmf");

Now that we’ve loaded the arguments, we have access to two properties: knownArgs and missingArgs . Each object in the array of known arguments contains the argument’s name, value, and details about where it is located. For example:

{
"argName": "host",
"dataType": "string",
"argValue": "example.com",
"argLoc": {
"locType": ProfLocType.TEAM_CONFIG,
"osLoc": "~/.zowe/zowe.config.json",
"jsonLoc": "profiles.lpar1.profiles.zosmf.properties.host"
},
"secure": false
}

If the secure property is true, then the value of the argument is not loaded immediately. This prevents sensitive data from being leaked accidentally, and allows the knownArgs object to be safely logged.

When you need access to a secure value, you can obtain it with the loadSecureArg method. For example, to load all secure values at once:

zosmfArgs.knownArgs.forEach((arg) => {
if (arg.secure) arg.argValue = profInfo.loadSecureArg(arg);
});

For arguments that have not been found anywhere, those arguments are listed in the missingArgs array. The object structure for a missing arg is essentially the same as the known arg object shown above, but without the value and location since those are unknown. Using the list of missing args provided by the API, it is easy to prompt a user to enter the missing values.

To avoid prompting the user for missing values again, it may be desirable to save profile information back to disk. The ProfileInfo API doesn’t include methods for saving profiles, since Imperative already contains easy-to-use APIs for saving properties to a team configuration or old style profiles. For example, the following statement will update the port number of a z/OSMF profile in a team configuration.

profInfo.getTeamConfig().set(
"profiles.lpar1.profiles.zosmf.properties.port", 443);
await profInfo.getTeamConfig().save(false);

Using the ProfileInfo API in a VS Code extension

A common use case for loading Zowe profiles is in a VS Code extension. Here’s an example of using the ProfileInfo API in a VS Code extension that combines everything mentioned above:

Updates

Since this article was originally published, the following functionality has been added to the ProfileInfo API.

  • Added a new function named createSession to create a session from an array of IProfArgAttrs, which has been retrieved from other ProfileInfo functions.
  • Added a new option named getSecureVals to the mergeArgsForXXX( ) functions. That option will automatically get the actual values for secure arguments, instead of just placeholders, which otherwise require apps to call a second function loadSecureArg( ).

Summary

The ProfileInfo API is a new utility that reduces the effort for GUI apps to retrieve Zowe profile property values. It also enables such apps to be compatible with the new Zowe team configuration, while automatically providing backward compatibility with old-style profiles.

Finding out more

If you enjoyed this blog checkout more Zowe blogs here. Or, ask a question and join the conversation on the Open Mainframe Project Slack Channel #Zowe-dev, #Zowe-user or #Zowe-onboarding. If this is your first time using the OMP slack channel register here.

Zowe is owned and managed by the Open Mainframe Project which is a Linux Foundation project.

--

--

Gene Johnston
Zowe
Writer for

I am a principal software engineer at Broadcom and a contributor to the Command Line Interface component of the Zowe project.