I am looking at files under /prod/$pid/attr
current exec fscreate keycreate prev sockcreate
anybody know what do these files do ?
Proc = process information for pseudofilesystem
/proc/[pid]/attr = Security attributes
/exec = represents the attributes assigned to the process / this is needed to support role/domain transitions
/fscreate = represents the attributes to assign files created by subsequent calls - mkdir - symlink
/keycreate = if/when a process writes a security context into this file all previous keys will be labelled with this context
/prev = shows previous values /proc/[PID]/attr/current
/sockcreate = if/when a process writes security context into this file all the previously created sockets will be labelled with this context
Related
I'm trying to manipulate the Audit screen (SM205510) through code, using a graph object. The operation of the screen has processes that seem to work when a screen ID is selected in the header. This is my code to create a new record:
Using PX.Data;
Using PX.Objects.SM;
var am = PXGraph.CreateInstance<AUAuditMaintenance>();
AUAuditSetup auditsetup = new AUAuditSetup();
auditsetup.ScreenID = "GL301000";
auditsetup = am.Audit.Insert(auditsetup);
am.Actions.PressSave();
Now, when I execute the code above, it creates a record in the AUAuditSetup table just fine - but it doesn't automatically create the AUAuditTable records the way they are auto-generated in the screen (I realize that the records aren't in the database yet) - but how can I get the graph object to auto-generate the AUAuditTable records in the cache the way they are in the screen?
I've tried looking at the source code for the Audit screen - but it just shows blank, like there's nothing there. I look in the code repository in Visual Studio and I don't see any file for AUAuditMaintenance either, so I can't see any process that I could run in the graph object that would populate those AUAuditTable records.
Any help would be appreciated.
Thanks...
If I had such a need, to manipulate Audit screen records, I'd rather create my own graph and probably generate DAC class. Also I'd add one more column UsrIsArtificial and set it to false by default. And then manage them as ordinary records, but each time I'll add something, I'd set field UsrIsArtificial to false.
You can hardly find how that records are managed at graph level because that records are created and handled on on Graph level, but on framework level. Also think twice or even more about design, as direct writing into Audit history may cause confusion for users in the system of what was caused by user, and what was caused by your code. From that point of view I would rather add one more additional table, then add confusion to existing one.
Acumatica support provided this solution, which works beautifully (Hat tip!):
var screenID = "GL301000"; //"SO303000";
var g = PXGraph.CreateInstance<AUAuditMaintenance>();
//Set Header Current
g.Audit.Current = g.Audit.Search<AUAuditSetup.screenID>(screenID);
if (g.Audit.Current == null) //If no Current then insert
{
var header = new AUAuditSetup();
header.ScreenID = screenID;
header.Description = "Test Audit";
header = g.Audit.Insert(header);
}
foreach (AUAuditTable table in g.Tables.Select())
{
table.IsActive = true;
//Sets Current for Detail
g.Tables.Current = g.Tables.Update(table);
foreach (AUAuditField field in g.Fields.Select())
{
field.IsActive = false;
g.Fields.Update(field);
}
}
g.Actions.PressSave();
I need to :
1. Create a single page location application
2. Display all the asset present in the selected location in a table
3. Provide a button from which user can navigate to WOTRACK to view all the workorder(s) created on selected location and its asset(s).
I am facing difficulty in the 3rd one. I have tried Launch in Context and it is working fine except am not able to pass sql query like 'location={location} and assetnum in ({asset.assetnum})'. I need to filter workorders with particular location and all its assets.
I tried to save all the assets in the location to a Non-persistant attribute and passing the values of the attribute in the Launch in context url, Its working as expected but to do so I have written a script on 'Initialize value' which is causing performance issues.
script goes like this:
from psdi.server import MXServer;
from psdi.mbo import MboConstants;
if app == "LOCATION1" :
if mbo.getString("LOCATION") is not None:
Locsite = mbo.getString("SITEID")
desc = mbo.getString("DESCRIPTION")
MaxuserSet = MXServer.getMXServer().getMboSet("MAXUSER", mbo.getUserInfo())
MaxuserSet.setWhere(" userid='"+user+"' ")
MaxuserSet.reset()
UserSite = MaxuserSet.getMbo(0).getString("DEFSITE")
if Locsite == UserSite:
AssetSet = mbo.getMboSet("ASSET")
AssetSet.setFlag(MboConstants.DISCARDABLE, True);
if not AssetSet.isEmpty():
AssetList = ""
AssetMbo = AssetSet.moveFirst()
while AssetMbo is not None:
AssetList = AssetList + str(AssetMbo.getString("ASSETNUM")) + "%2C"
AssetMbo = AssetSet.moveNext()
mbo.setValue("non-persitant",str(AssetList),11L)
and in the LIC url i have given : 'http://xx.x.x.xx/maximo/ui/?event=loadapp&value=wotrack&tabid=List&additionalevent=useqbe&additionaleventvalue=location={LOCATION}|assetnum={non-persistant}'
Is there any other feasible solution to the requirement?
Thanks in Advance
Launch In Context is better used for sending the user to an outside-of-Maximo application and passing along some data from inside-Maximo to provide context in that external app.
What you are doing sounds like a good place to use a workflow process with an Interaction node. The developer tells the Interaction node which app to take the user to and which Relationship to use to find the data the user should work with there.
Why don't you add a table control inside the table details (expanded table row) and show a list of the work orders there. From the WONUM in that table, you could have an app link to take them to WOTRACK, if they want more details about a particular work order. No customization (automation scripting) needed. No workflow needed. Nice and simple.
I have created a non-persistent attribute in my WoActivity table named VDS_COMPLETE. it is a bool that get changed by a checkbox in one of my application.
I am trying to make a automatisation script in Python to change the status of every task a work order that have been check when I save the WorkOrder.
I don't know why it isn't working but I'm pretty sure I'm close to the answer...
Do you have an idea why it isn't working? I know that I have code in comments, I have done a few experimentations...
from psdi.mbo import MboConstants
from psdi.server import MXServer
mxServer = MXServer.getMXServer()
userInfo = mxServer.getUserInfo(user)
mboSet = mxServer.getMboSet("WORKORDER")
#where1 = "wonum = :wonum"
#mboSet .setWhere(where1)
#mboSet.reset()
workorderSet = mboSet.getMbo(0).getMboSet("WOACTIVITY", "STATUS NOT IN ('FERME' , 'ANNULE' , 'COMPLETE' , 'ATTDOC')")
#where2 = "STATUS NOT IN ('FERME' , 'ANNULE' , 'COMPLETE' , 'ATTDOC')"
#workorderSet.setWhere(where2)
if workorderSet.count() > 0:
for x in range(0,workorderSet.count()):
if workorderSet.getString("VDS_COMPLETE") == 1:
workorder = workorderSet.getMbo(x)
workorder.changeStatus("COMPLETE",MXServer.getMXServer().getDate(), u"Script d'automatisation", MboConstants.NOACCESSCHECK)
workorderSet.save()
workorderSet.close()
It looks like your two biggest mistakes here are 1. trying to get your boolean field (VDS_COMPLETE) off the set (meaning off of the collection of records, like the whole table) instead of off of the MBO (meaning an actual record, one entry in the table) and 2. getting your set of data fresh from the database (via that MXServer call) which means using the previously saved data instead of getting your data set from the screen where the pending changes have actually been made (and remember that non-persistent fields do not get saved to the database).
There are some other problems with this script too, like your use of "count()" in your for loop (or even more than once at all) which is an expensive operation, and the way you are currently (though this may be a result of your debugging) not filtering the work order set before grabbing the first work order (meaning you get a random work order from the table) and then doing a dynamic relationship off of that record (instead of using a normal relationship or skipping the relationship altogether and using just a "where" clause), even though that relationship likely already exists.
Here is a Stack Overflow describing in more detail about relationships and "where" clauses in Maximo: Describe relationship in maximo 7.5
This question also has some more information about getting data from the screen versus new from the database: Adding a new row to another table using java in Maximo
I have what seemed like a fairly simple requirement for a process that im beginning to question is even possible.
The image below shows my current process. I am trying to achieve two things:
A user creates an initial user task for adding a note, they should be able to add as many notes as they wish with one user task per note
A new sub-process is spawned for each new note (user task) that the user has created.
The process above presents the following problems:
A sub-process should be spawned for each task, however they seem to overwrite each other
Im not sure if the sub-process requires a unique id for each new sub-process spawned
So it turns out that the solution to this question requires a bit of scripting using groovy.
Below is the updated process model diagram, in it I start a new instance of the Complete Task process using a script task then if the user wishes to add more tasks the exclusive gateway can return the user to the Create task (user task) OR finish the process.
I clear down any values in the fields held within the user task within the script task before I pass the scope back to the user task.
The image below shows my Complete Task process that gets called by the main process using a script
Here I avoid using parallel gateways in preference of creating a new instance of the Create Task (user task) and a new instance of the Complete task process (not subprocess) via means of the script.
To start a new instance of the Complete Task process we have to start the process using the function startProcessInstanceByKeyAndTenantId() under a runtimeService instance for the process, although I could also use startProcessInstanceByIdAndTenantId():
//Import required libraries
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
//instantiate RunTimeService instance
RuntimeService runtimeService = execution.getEngineServices().getRuntimeService();
//get tenant id
String tenantId = execution.getTenantId();
//variables Map
Map<String, Object> variables = runtimeService.getVariablesLocal(execution.getProcessInstanceId());
//start process (processId, variables, tenantId)
ProcessInstance completeTask = runtimeService.startProcessInstanceByKeyAndTenantId("CompleteTask", variables, tenantId);
//Clear variables to create a fresh task
execution.setVariable("title", "");
execution.setVariable("details", "");
Using this approach I avoid creating multiple subprocesses from the parent process and instead create multiple processes that run separate from the parent process. This benefits me as if the parent process completes the others continue to run.
Seems like you are updating only one variable (or a single set of variables) as a result of each task. This will override the previous value. use distinct variables, or append something before each variable to mark it unique for the task/ sub-process completed. see collapsed sub-process
Yes, each sub process gets its own unique execution id, But the main execution ID or process instance ID remains same
So a user has a primary group and may belong to other supplementary group.
suppose user A primary group is G and supplementary groups G+1,G+2
User A runs a program is it possible to change group id to G+1
by default i know the group id will be set to G but an error is thrown when i run below program .erroris: Operation not permitted,where 4 is supplemental group a user belongs too.
According to the Manual ERRORS
EPERM The calling process is not privileged (does not have the CAP_SETGID capability), and gid does not match the real group ID or saved set-group-ID ofthe calling process.
How to list capability of a process ?
what does the saved set-group-id means ?
int
main ()
{
int x = 0;
char *error = "erroris";
x = setgid (4);
printf ("%d", x);
perror (error);
}
Too many questions in one question!
Problem 1: cannot use setgid to change to a different goup id
Reasons for failure: User is not root, User is not euid 0, User does not have CAP_SETGID
Problem 2: How do I list the capabilities of a process
Answer 2: Use cap_get_proc and cap_to_text to list the capabilities of a process
Problem 3: What does the saved set-group-id mean
Answer 3: When you use one of the sete*id() calls successfully, it records the old one in the saved id. This allows you to revert back to the saved value because this is one of the ids you're permitted to change to using the set call.