Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

V1next history log #578

Open
wants to merge 47 commits into
base: v0.10.x
Choose a base branch
from
Open

V1next history log #578

wants to merge 47 commits into from

Conversation

isc-shuliu
Copy link
Collaborator

@isc-shuliu isc-shuliu commented Oct 3, 2024

Implement #366
TODO List

  • Figure out what "committed" is
  • Work out the "history" command
  • Add public API for querying history
  • Record recursively loaded/installed modules
  • Properly implement "commit"
  • Allow more matching patterns when filtering histories
  • Display log entries in a prettier manner
  • Command to see the details of a history log by ID
  • Command to show supported columns for filtering
  • Allow specifying direction for sorting and limit max number of rows

@isc-tleavitt
Copy link
Contributor

isc-tleavitt commented Oct 4, 2024

Re: "committed" - this would track, in non-dev mode, if installation was attempted but failed in some way - that is, it would be set to 0 in this case and 1 if installation succeeded. The reason for the failure (probably a %Status) would be worth recording as well for a failed installation.

@isc-kiyer
Copy link
Collaborator

Re: "committed" - this would track, in non-dev mode, if installation was attempted but failed in some way - that is, it would be set to 0 in this case and 1 if installation succeeded. The reason for the failure (probably a %Status) would be worth recording as well for a failed installation.

This comes into the overall lifecycle rework where we flag the phase in which a module reached during install and track the error that occurred as well. For modules in dev mode, can permit resuming install from the failed phase onwards and for non-dev mode, always start from scratch for the module.

@isc-shuliu
Copy link
Collaborator Author

isc-shuliu commented Oct 8, 2024

Not sure why 2c240de doesn't work.

I have a local registry with modA and modB, where modB depends on modA. When installing modB, IPM will call %IPM.Utils.Module:LoadDependencies(), which uses %SYSTEM.WorkMgr to spawn a new process that runs ..LoadModuleReference().

The change in commit 2c240de is simple. We create a %Persistent history log object, save it in database, and pass the ID to the work unit. In the work unit, we save the success/failure and TimeEnd.

However, when calling %Save() from the spawned process, it raises the error Failed to acquire exclusive lock on instance of '%IPM.General.History. Why is there any lock involved?

@isc-shuliu
Copy link
Collaborator Author

isc-shuliu commented Oct 8, 2024

It appears the lock is created because we're in a transaction. (Tried stepping through the code while monitoring management portal, lock disappears after manually running TCOMMIT)

Copy link
Contributor

@isc-tleavitt isc-tleavitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few really minor comments, but I think this is great overall.

<Value>CommandString</Value>
</Value>
</Data>
<DataLocation>^%IPM.General.HistoryD</DataLocation>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this mapped?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The data is mapped to each namespace where %IPM package is mapped. Do we want to separate them?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, that'll be fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify: there are no global mappings for the data but since it is a % global, will live in IRISSYS? I think its best to have this be a non-% global and can remove Namespace to scope history by namespace (like the rest of IPM).

@isc-shuliu
Copy link
Collaborator Author

@isc-tleavitt
Based on your feedback, I changed the time diff display to always show seconds and exposed API queries instead of API methods.

Currently, the table data is shared among all namespaces where %IPM is mapped. Do we want to separate them?

@isc-tleavitt
Copy link
Contributor

I think this is good now, just need @isc-kiyer's review

@isc-kiyer isc-kiyer requested a review from isc-eneil October 24, 2024 14:14
Copy link
Collaborator

@isc-kiyer isc-kiyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@isc-shuliu This is a great and exhaustive feature! My comments and some questions are up

<parameter name="argument" required="false" description="Argument for `details` command" />
<example description="Show history of all packages in the current namespace in descending order">history find </example>
<example description="Show history of all packages in the current namespace where command starts with &quot;load&quot;">history find -DCommandString="load*"</example>
<example description="Show history of all packages in the current namespace where start time is later than 2000-01-01 00:00:00">history find -DTimeStart=">2000-01-01 00:00:00"</example>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than using -D modifiers, may be nice to be able to add sub-modifiers and enum for parameters or modifiers. Then for history, can have enum for the action parameter and sub-modifiers tied to different parameter enums. Is a bit extensive and invasive but I think it will be helpful for many other commands.

Happy to talk through design of this

/// Get the history of all installations, uninstalls, and loads in given namespace
/// The filter argument is a multidimensional array with structure
/// filter(columnName) = value
/// Where value can optionally start with >, >=, <, <=, =, <> or contain * to indicate a wildcard
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than value starting with such things, perhaps make value a $ListBuild? The possible issue with it starting with that is that the property's value may actually be using one of these symbols.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea, my concern is that It can be cumbersome for users to construct a command string that contains $ListBuild()s. They would need to do something like

zpm "history find -DTimeStart=" _ $lb(">", "2000-01-01 00:00:00")

And I can't think of a way for it to work in interactive mode:

USER>zpm

=============================================================================
|| Welcome to the Package Manager Shell (ZPM). Version:                    ||
|| Enter q/quit to exit the shell. Enter ?/help to view available commands ||
|| Current registry https://pm.community.intersystems.com                  ||
=============================================================================
zpm:USER>history find -DTimeStart=???

@isc-tleavitt
Copy link
Contributor

This should account for #704 (the pitfalls of being stuck here for a while, while we've been focused on more pressing things...)

Copy link
Collaborator

@isc-kiyer isc-kiyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@isc-shuliu another round of comments. Also, worthwhile adding unit tests since this is a brand new feature. Some test cases I can think about:

  • simple commands with no modifiers
  • commands with valid modifiers
  • commands with invalid modifiers
  • modules in dev and non-dev mode
  • testing all commands (load, install, uninstall)
  • filtering
  • altering number of history results to keep
  • searching per namespace vs globally
  • error handling for invalid filtering columns

<Value>CommandString</Value>
</Value>
</Data>
<DataLocation>^%IPM.General.HistoryD</DataLocation>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify: there are no global mappings for the data but since it is a % global, will live in IRISSYS? I think its best to have this be a non-% global and can remove Namespace to scope history by namespace (like the rest of IPM).

/// Action of this history record. Can be load, install, or uninstall
Property Action As %String(VALUELIST = ",load,install,uninstall") [ Required ];

/// Name of the package being loaded/installed/uninstall. This is not necessarily requried. E.g., when loading a nonexistent directory.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: typo for required

{

/// Action of this history record. Can be load, install, or uninstall
Property Action As %String(VALUELIST = ",load,install,uninstall") [ Required ];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@isc-shuliu What about module actions like compile, activate etc. Are these things we want to log? Or just in general, all commands from the zpm shell?
cc @isc-tleavitt

Property NameSpace As %String [ InitialExpression = {$NAMESPACE}, Required ];

/// User who initiated the action
Property UserName As %String [ InitialExpression = {$USERNAME}, Required ];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Use %Library.Username

Property Committed As %Boolean [ InitialExpression = 0, Required ];

/// The command string that triggered the action
Property CommandString As %String(MAXLEN = 8192) [ Required ];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does command string need a maxlen?

/// Where value can optionally start with >, >=, <, <=, =, <> or contain * to indicate a wildcard
ClassMethod GetHistory(ByRef filter, ascend As %Boolean = 0, limit As %Integer = 0, namespace As %String) As %SQL.StatementResult
{
Set limit = +limit // Coerce to number to prevent SQL injection
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use ? like in where clauses as TOP ? to prevent SQL injection

/// Output "clause" is the SQL WHERE clause as a string, container zero or more ? placeholders
/// The "varargs" is an array of values to be substituted in the ? placeholders.
/// The "varargs" may already be populated with values, and new values will be appended to it.
ClassMethod ConstructSQLWhere(filter As %String, namespace As %String, Output clause As %String, ByRef varargs As %String) As %Status [ Internal ]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: here filter should be ByRef since it a multi-dim array

@@ -1889,6 +1915,19 @@ ClassMethod LoadFromRepo(tDirectoryName, ByRef tParams) [ Internal ]
}

ClassMethod Load(ByRef pCommandInfo) [ Internal ]
{
Set devMode = $Get(pCommandInfo("data", "DeveloperMode"), 1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should devMode default be 0? Without -dev flag, it is 0 right?


#dim log As %IPM.General.History
Set log = ##class(%IPM.General.History).InstallInit(tModuleName)
Set devMode = $Get(tParams("DeveloperMode"), 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no tParams here. Did you mean to write pCommandInfo("data","DeveloperMode") ?

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants