12 changed files with 1611 additions and 1611 deletions
@ -1,111 +1,111 @@ |
|||||
Contributor Agreement |
Contributor Agreement |
||||
|
|
||||
|
|
||||
|
|
||||
Version 1.1 |
Version 1.1 |
||||
|
|
||||
|
|
||||
|
|
||||
Contributions to this software are accepted only when they are |
Contributions to this software are accepted only when they are |
||||
|
|
||||
properly accompanied by a Contributor Agreement. The Contributor |
properly accompanied by a Contributor Agreement. The Contributor |
||||
|
|
||||
Agreement for this software is the Developer's Certificate of Origin |
Agreement for this software is the Developer's Certificate of Origin |
||||
|
|
||||
1.1 (DCO) as provided with and required for accepting contributions |
1.1 (DCO) as provided with and required for accepting contributions |
||||
|
|
||||
to the Linux kernel. |
to the Linux kernel. |
||||
|
|
||||
|
|
||||
|
|
||||
In each contribution proposed to be included in this software, the |
In each contribution proposed to be included in this software, the |
||||
|
|
||||
developer must include a "sign-off" that denotes consent to the |
developer must include a "sign-off" that denotes consent to the |
||||
|
|
||||
terms of the Developer's Certificate of Origin. The sign-off is |
terms of the Developer's Certificate of Origin. The sign-off is |
||||
|
|
||||
a line of text in the description that accompanies the change, |
a line of text in the description that accompanies the change, |
||||
|
|
||||
certifying that you have the right to provide the contribution |
certifying that you have the right to provide the contribution |
||||
|
|
||||
to be included. For changes provided in source code control (for |
to be included. For changes provided in source code control (for |
||||
|
|
||||
example, via a Git pull request) the sign-off must be included in |
example, via a Git pull request) the sign-off must be included in |
||||
|
|
||||
the commit message in source code control. For changes provided |
the commit message in source code control. For changes provided |
||||
|
|
||||
in email or issue tracking, the sign-off must be included in the |
in email or issue tracking, the sign-off must be included in the |
||||
|
|
||||
email or the issue, and the sign-off will be incorporated into the |
email or the issue, and the sign-off will be incorporated into the |
||||
|
|
||||
permanent commit message if the contribution is accepted into the |
permanent commit message if the contribution is accepted into the |
||||
|
|
||||
official source code. |
official source code. |
||||
|
|
||||
|
|
||||
|
|
||||
If you can certify the below: |
If you can certify the below: |
||||
|
|
||||
|
|
||||
|
|
||||
Developer's Certificate of Origin 1.1 |
Developer's Certificate of Origin 1.1 |
||||
|
|
||||
|
|
||||
|
|
||||
By making a contribution to this project, I certify that: |
By making a contribution to this project, I certify that: |
||||
|
|
||||
|
|
||||
|
|
||||
(a) The contribution was created in whole or in part by me and I |
(a) The contribution was created in whole or in part by me and I |
||||
|
|
||||
have the right to submit it under the open source license |
have the right to submit it under the open source license |
||||
|
|
||||
indicated in the file; or |
indicated in the file; or |
||||
|
|
||||
|
|
||||
|
|
||||
(b) The contribution is based upon previous work that, to the best |
(b) The contribution is based upon previous work that, to the best |
||||
|
|
||||
of my knowledge, is covered under an appropriate open source |
of my knowledge, is covered under an appropriate open source |
||||
|
|
||||
license and I have the right under that license to submit that |
license and I have the right under that license to submit that |
||||
|
|
||||
work with modifications, whether created in whole or in part |
work with modifications, whether created in whole or in part |
||||
|
|
||||
by me, under the same open source license (unless I am |
by me, under the same open source license (unless I am |
||||
|
|
||||
permitted to submit under a different license), as indicated |
permitted to submit under a different license), as indicated |
||||
|
|
||||
in the file; or |
in the file; or |
||||
|
|
||||
|
|
||||
|
|
||||
(c) The contribution was provided directly to me by some other |
(c) The contribution was provided directly to me by some other |
||||
|
|
||||
person who certified (a), (b) or (c) and I have not modified |
person who certified (a), (b) or (c) and I have not modified |
||||
|
|
||||
it. |
it. |
||||
|
|
||||
|
|
||||
|
|
||||
(d) I understand and agree that this project and the contribution |
(d) I understand and agree that this project and the contribution |
||||
|
|
||||
are public and that a record of the contribution (including all |
are public and that a record of the contribution (including all |
||||
|
|
||||
personal information I submit with it, including my sign-off) is |
personal information I submit with it, including my sign-off) is |
||||
|
|
||||
maintained indefinitely and may be redistributed consistent with |
maintained indefinitely and may be redistributed consistent with |
||||
|
|
||||
this project or the open source license(s) involved. |
this project or the open source license(s) involved. |
||||
|
|
||||
|
|
||||
|
|
||||
then you just add a line saying |
then you just add a line saying |
||||
|
|
||||
|
|
||||
|
|
||||
Signed-off-by: Random J Developer <random@developer.example.org> |
Signed-off-by: Random J Developer <random@developer.example.org> |
||||
|
|
||||
|
|
||||
|
|
||||
using your real name (sorry, no pseudonyms or anonymous contributions.) |
using your real name (sorry, no pseudonyms or anonymous contributions.) |
||||
@ -1,59 +1,59 @@ |
|||||
**pyviyatools Install Intructions** |
**pyviyatools Install Intructions** |
||||
|
|
||||
The pyviyatools are a set of command-line tools that call the SAS Viya REST API's from python. The tools can be used to make direct calls to any rest-endpoint (like a CURL command) or to build additional tools that make multiple rest calls to provide more complex functionality. |
The pyviyatools are a set of command-line tools that call the SAS Viya REST API's from python. The tools can be used to make direct calls to any rest-endpoint (like a CURL command) or to build additional tools that make multiple rest calls to provide more complex functionality. |
||||
|
|
||||
**INSTALL** |
**INSTALL** |
||||
|
|
||||
The tools are a package of files and should be downloaded as such. The individual files are not useable without the package. |
The tools are a package of files and should be downloaded as such. The individual files are not useable without the package. |
||||
|
|
||||
The tools should be installed on the same machine that hosts the Viya command-line interfaces(CLI). The following command will install a copy of the tools in a sub-directory(pyviyatools) of the current directory. |
The tools should be installed on the same machine that hosts the Viya command-line interfaces(CLI). The following command will install a copy of the tools in a sub-directory(pyviyatools) of the current directory. |
||||
|
|
||||
*git clone https://github.com/sassoftware/pyviyatools.git* |
*git clone https://github.com/sassoftware/pyviyatools.git* |
||||
|
|
||||
**Authenticate** |
**Authenticate** |
||||
|
|
||||
The pyviya tools use the sas-admin auth CLI to authenticate to Viya. To use the tool you must create a profile and authenticate. This process is documented in the SAS Viya Administration guide here. |
The pyviya tools use the sas-admin auth CLI to authenticate to Viya. To use the tool you must create a profile and authenticate. This process is documented in the SAS Viya Administration guide here. |
||||
|
|
||||
http://documentation.sas.com/?cdcId=calcdc&cdcVersion=3.3&docsetId=calcli&docsetTarget=n1e2dehluji7jon1gk69yggc6i28.htm&locale=en |
http://documentation.sas.com/?cdcId=calcdc&cdcVersion=3.3&docsetId=calcli&docsetTarget=n1e2dehluji7jon1gk69yggc6i28.htm&locale=en |
||||
|
|
||||
|
|
||||
If your environment is enabled for Transport Layer Security (TLS), you must set the SSL_CERT_FILE environment variable to the path location of the trustedcerts.pem file (if using the SAS default truststore) |
If your environment is enabled for Transport Layer Security (TLS), you must set the SSL_CERT_FILE environment variable to the path location of the trustedcerts.pem file (if using the SAS default truststore) |
||||
or the path location of your site-signed certificate (if using an internal truststore). |
or the path location of your site-signed certificate (if using an internal truststore). |
||||
|
|
||||
In addition you may need to set REQUESTS_CA_BUNDLE to the certificate location so that the requests library can find the certificates. |
In addition you may need to set REQUESTS_CA_BUNDLE to the certificate location so that the requests library can find the certificates. |
||||
|
|
||||
The tool will automatically use the default profile. |
The tool will automatically use the default profile. |
||||
|
|
||||
1. To create a profile as a SAS Administrator logon to the machine that contains the Viya CLI's |
1. To create a profile as a SAS Administrator logon to the machine that contains the Viya CLI's |
||||
2. Run */opt/sas/viya/home/bin/sas-admin profile init* and when prompter enter the base endpoint of your Viya server for example: http://myviyaserver.blah.com. You may enter your personal preference at the other prompts. |
2. Run */opt/sas/viya/home/bin/sas-admin profile init* and when prompter enter the base endpoint of your Viya server for example: http://myviyaserver.blah.com. You may enter your personal preference at the other prompts. |
||||
3. After you create the profile there are two options to authenticate |
3. After you create the profile there are two options to authenticate |
||||
* Run */opt/sas/viya/home/bin/sas-admin auth login* to authenticate to Viya enter the userid and password of the SAS Administrator when prompted. |
* Run */opt/sas/viya/home/bin/sas-admin auth login* to authenticate to Viya enter the userid and password of the SAS Administrator when prompted. |
||||
* Create an .authinfo file in your home directory with your userid and password and use **loginviauthinfo.py** to authenticate with the credentials in the file (you can use different authinfo files with the -f option) |
* Create an .authinfo file in your home directory with your userid and password and use **loginviauthinfo.py** to authenticate with the credentials in the file (you can use different authinfo files with the -f option) |
||||
|
|
||||
The CLI allows for multiple profiles. To use a profile other than the default profile, for example newprofile |
The CLI allows for multiple profiles. To use a profile other than the default profile, for example newprofile |
||||
|
|
||||
1. Create a named profile *sas-admin --profile newprofile profile init* |
1. Create a named profile *sas-admin --profile newprofile profile init* |
||||
2. Logon with the named profile *sas-admin --profile newprofile auth login* |
2. Logon with the named profile *sas-admin --profile newprofile auth login* |
||||
3. Set the SAS_CLI_PROFILE environment variable to the name of the profile |
3. Set the SAS_CLI_PROFILE environment variable to the name of the profile |
||||
* LINUX: *export SAS_CLI_PROFILE=newprofile* |
* LINUX: *export SAS_CLI_PROFILE=newprofile* |
||||
* WINDOWS: *set SAS_CLI_PROFILE=newprofile* |
* WINDOWS: *set SAS_CLI_PROFILE=newprofile* |
||||
|
|
||||
4. To revert to using the default variable reset the environment variable |
4. To revert to using the default variable reset the environment variable |
||||
|
|
||||
* LINUX: *unset SAS_CLI_PROFILE* |
* LINUX: *unset SAS_CLI_PROFILE* |
||||
* WINDOWS: *set SAS_CLI_PROFILE=* |
* WINDOWS: *set SAS_CLI_PROFILE=* |
||||
|
|
||||
The tools are self-documenting, for help on any tool call the tool passing -h or --help. |
The tools are self-documenting, for help on any tool call the tool passing -h or --help. |
||||
|
|
||||
|
|
||||
**TEST** |
**TEST** |
||||
|
|
||||
1. Execute a test call. Change directory to your install directory and run: |
1. Execute a test call. Change directory to your install directory and run: |
||||
|
|
||||
*callrestapi.py -e /folders/folders -m get* |
*callrestapi.py -e /folders/folders -m get* |
||||
|
|
||||
The call should return the JSON for the folders in the viya deployment. Be patient it might take a few seconds the first time. |
The call should return the JSON for the folders in the viya deployment. Be patient it might take a few seconds the first time. |
||||
|
|
||||
2. To see the current setup, including python and package versions, environment variable settings, profile information and current user. Run |
2. To see the current setup, including python and package versions, environment variable settings, profile information and current user. Run |
||||
|
|
||||
*showsetup.py* |
*showsetup.py* |
||||
|
|||||
@ -1,284 +1,284 @@ |
|||||
# Python Tools for SAS Viya |
# Python Tools for SAS Viya |
||||
|
|
||||
The pyviyatools are a set of command-line tools that call the SAS Viya REST API's from python. The tools can be used to make direct calls to any rest-endpoint (like a CURL command) or to build additional tools that make multiple rest calls to provide more complex functionality. The tools are designed to be used in conjunction with the sas-admin command line interfaces(CLI). |
The pyviyatools are a set of command-line tools that call the SAS Viya REST API's from python. The tools can be used to make direct calls to any rest-endpoint (like a CURL command) or to build additional tools that make multiple rest calls to provide more complex functionality. The tools are designed to be used in conjunction with the sas-admin command line interfaces(CLI). |
||||
|
|
||||
## Getting Started |
## Getting Started |
||||
|
|
||||
### Documentation |
### Documentation |
||||
|
|
||||
You can find the SAS Open API's documented: https://developer.sas.com/apis/rest/ |
You can find the SAS Open API's documented: https://developer.sas.com/apis/rest/ |
||||
|
|
||||
Some other useful links |
Some other useful links |
||||
|
|
||||
* https://developer.sas.com/apis/rest/#filters |
* https://developer.sas.com/apis/rest/#filters |
||||
* https://developer.sas.com/apis/rest/#pagination |
* https://developer.sas.com/apis/rest/#pagination |
||||
* https://developer.sas.com/apis/rest/#sorting |
* https://developer.sas.com/apis/rest/#sorting |
||||
|
|
||||
### Prerequisites |
### Prerequisites |
||||
|
|
||||
The tools requires either python 2 or python 3. |
The tools requires either python 2 or python 3. |
||||
|
|
||||
The following python libraries are used: |
The following python libraries are used: |
||||
|
|
||||
* requests http://docs.python-requests.org/en/master/ |
* requests http://docs.python-requests.org/en/master/ |
||||
* sys |
* sys |
||||
* json |
* json |
||||
* os |
* os |
||||
* netrc |
* netrc |
||||
* subprocess |
* subprocess |
||||
* platform |
* platform |
||||
* argeparse |
* argeparse |
||||
|
|
||||
|
|
||||
### Installing |
### Installing |
||||
|
|
||||
Please use the installation intructions in the file INSTALL.md [INSTALL.md](INSTALL.md) |
Please use the installation intructions in the file INSTALL.md [INSTALL.md](INSTALL.md) |
||||
|
|
||||
### Running |
### Running |
||||
|
|
||||
The pyviya tools use the sas-admin auth CLI to authenticate to Viya. To use the tool you must create a profile and authenticate. |
The pyviya tools use the sas-admin auth CLI to authenticate to Viya. To use the tool you must create a profile and authenticate. |
||||
|
|
||||
This process is documented in the SAS Viya Administration guide here. |
This process is documented in the SAS Viya Administration guide here. |
||||
|
|
||||
http://documentation.sas.com/?cdcId=calcdc&cdcVersion=3.3&docsetId=calcli&docsetTarget=n1e2dehluji7jon1gk69yggc6i28.htm&locale=en |
http://documentation.sas.com/?cdcId=calcdc&cdcVersion=3.3&docsetId=calcli&docsetTarget=n1e2dehluji7jon1gk69yggc6i28.htm&locale=en |
||||
|
|
||||
#### Creating a Profile and Logging on |
#### Creating a Profile and Logging on |
||||
|
|
||||
The tool will automatically use the default profile. |
The tool will automatically use the default profile. |
||||
|
|
||||
1. To create a profile as a SAS Administrator logon to the machine that contains the Viya CLI's |
1. To create a profile as a SAS Administrator logon to the machine that contains the Viya CLI's |
||||
2. Run */opt/sas/viya/home/bin/sas-admin profile init* and when prompter enter the base endpoint of your Viya server for example: http://myviyaserver.blah.com. You may enter your personal preference at the other prompts. |
2. Run */opt/sas/viya/home/bin/sas-admin profile init* and when prompter enter the base endpoint of your Viya server for example: http://myviyaserver.blah.com. You may enter your personal preference at the other prompts. |
||||
3. After you create the profile there are two options to authenticate |
3. After you create the profile there are two options to authenticate |
||||
* Run */opt/sas/viya/home/bin/sas-admin auth login* to authenticate to Viya enter the userid and password of the SAS Administrator when prompted. |
* Run */opt/sas/viya/home/bin/sas-admin auth login* to authenticate to Viya enter the userid and password of the SAS Administrator when prompted. |
||||
* Create an .authinfo file in your home directory with your userid and password and use **loginviauthinfo.py** to authenticate with the credentials in the file (you can use different authinfo files with the -f option) |
* Create an .authinfo file in your home directory with your userid and password and use **loginviauthinfo.py** to authenticate with the credentials in the file (you can use different authinfo files with the -f option) |
||||
|
|
||||
The CLI allows for multiple profiles. To use a profile other than the default profile, for example newprofile |
The CLI allows for multiple profiles. To use a profile other than the default profile, for example newprofile |
||||
|
|
||||
1. Create a named profile *sas-admin --profile newprofile profile init* |
1. Create a named profile *sas-admin --profile newprofile profile init* |
||||
2. Logon with the named profile *sas-admin --profile newprofile auth login* |
2. Logon with the named profile *sas-admin --profile newprofile auth login* |
||||
3. Set the SAS_CLI_PROFILE environment variable to the name of the profile |
3. Set the SAS_CLI_PROFILE environment variable to the name of the profile |
||||
* LINUX: *export SAS_CLI_PROFILE=newprofile* |
* LINUX: *export SAS_CLI_PROFILE=newprofile* |
||||
* WINDOWS: *set SAS_CLI_PROFILE=newprofile* |
* WINDOWS: *set SAS_CLI_PROFILE=newprofile* |
||||
|
|
||||
4. When the SAS_CLI_PROFILE is set the tool will use the profile stored in the variable |
4. When the SAS_CLI_PROFILE is set the tool will use the profile stored in the variable |
||||
5. To revert to using the default variable reset the environment variable |
5. To revert to using the default variable reset the environment variable |
||||
|
|
||||
* LINUX: *unset SAS_CLI_PROFILE* |
* LINUX: *unset SAS_CLI_PROFILE* |
||||
* WINDOWS: *set SAS_CLI_PROFILE=* |
* WINDOWS: *set SAS_CLI_PROFILE=* |
||||
|
|
||||
|
|
||||
The tools are self-documenting, for help on any tool call the tool passing -h or --help. |
The tools are self-documenting, for help on any tool call the tool passing -h or --help. |
||||
|
|
||||
python *\<pathtotool\>\<toolname.py\>* -h |
python *\<pathtotool\>\<toolname.py\>* -h |
||||
|
|
||||
|
|
||||
**Available Tools** |
**Available Tools** |
||||
|
|
||||
**callrestapi** |
**callrestapi** |
||||
|
|
||||
callrestapi is a general tool, and the building block for all the other tools. |
callrestapi is a general tool, and the building block for all the other tools. |
||||
|
|
||||
callrestapi will call the Viya REST API and return json or optionally a simplified output. It can call any viya REST method. (Like a curl command). |
callrestapi will call the Viya REST API and return json or optionally a simplified output. It can call any viya REST method. (Like a curl command). |
||||
|
|
||||
*usage: callrestapi.py [-h] -e ENDPOINT -m {get,put,post,delete} [-i INPUTFILE] [-a ACCEPTTYPE] [-c CONTENTTYPE] [-o {csv,json,simple}]* |
*usage: callrestapi.py [-h] -e ENDPOINT -m {get,put,post,delete} [-i INPUTFILE] [-a ACCEPTTYPE] [-c CONTENTTYPE] [-o {csv,json,simple}]* |
||||
|
|
||||
You must pass a method and endpoint. You can optionally pass json, content type headers or the -t flag to change output from json to basic text. |
You must pass a method and endpoint. You can optionally pass json, content type headers or the -t flag to change output from json to basic text. |
||||
|
|
||||
**List of some of the Additional Tools Available** |
**List of some of the Additional Tools Available** |
||||
|
|
||||
Additional tools provide more complex functionality by combining multiple calls to the callrestapi function, and post-processing the outpuit that is returned. |
Additional tools provide more complex functionality by combining multiple calls to the callrestapi function, and post-processing the outpuit that is returned. |
||||
|
|
||||
* **getfolderid** returns the id of the folder based on the full folder path |
* **getfolderid** returns the id of the folder based on the full folder path |
||||
* **deletefolder** deletes a folder based on the full folder path |
* **deletefolder** deletes a folder based on the full folder path |
||||
* **deletefolderandcontent** deletes a folder and any reports that are stored in the folder |
* **deletefolderandcontent** deletes a folder and any reports that are stored in the folder |
||||
* **movecontent** moves the content from a source to a target folder |
* **movecontent** moves the content from a source to a target folder |
||||
* **getconfigurationproperties** lists the name/value pairs of a configuration |
* **getconfigurationproperties** lists the name/value pairs of a configuration |
||||
* **testfolderaccess** tests if a user or group has access to a folder |
* **testfolderaccess** tests if a user or group has access to a folder |
||||
* **createbinarybackup.py** creates a binary backup job |
* **createbinarybackup.py** creates a binary backup job |
||||
* **createdomain.py** creates an authentication domain |
* **createdomain.py** creates an authentication domain |
||||
* **listrules.py** list authorization rules subset on a principal and/or a uri |
* **listrules.py** list authorization rules subset on a principal and/or a uri |
||||
* **loginviauthinfo.py** use an authinfo file to authenticate to the CLI |
* **loginviauthinfo.py** use an authinfo file to authenticate to the CLI |
||||
* **updateprefences.py** update preferences for a user or group of users |
* **updateprefences.py** update preferences for a user or group of users |
||||
* **updatedomain.py** Load a set of userids and passwords to a Viya domain from a csv file |
* **updatedomain.py** Load a set of userids and passwords to a Viya domain from a csv file |
||||
* **createfolders.py** Create a set of Viya folders from a csv file |
* **createfolders.py** Create a set of Viya folders from a csv file |
||||
* **explainaccess.py** Explains access for a folder, object or service endpoint |
* **explainaccess.py** Explains access for a folder, object or service endpoint |
||||
|
|
||||
Check back for additional tools and if you build a tool feel free to contribute it to the collection. |
Check back for additional tools and if you build a tool feel free to contribute it to the collection. |
||||
|
|
||||
## Examples |
## Examples |
||||
|
|
||||
The example calls assume you are in the directory where you installed the tools. If you are not you can prepemd the directory to the filename, for example /opt/pyviyatools/callrestapi.py |
The example calls assume you are in the directory where you installed the tools. If you are not you can prepemd the directory to the filename, for example /opt/pyviyatools/callrestapi.py |
||||
If you are using the tool on windows the syntax is: |
If you are using the tool on windows the syntax is: |
||||
|
|
||||
*python toolname.py* |
*python toolname.py* |
||||
|
|
||||
The following examples are Linux. |
The following examples are Linux. |
||||
|
|
||||
\# Login to Viya using default authinfo file ~/.authinfo |
\# Login to Viya using default authinfo file ~/.authinfo |
||||
*./loginviauthinfo.py* |
*./loginviauthinfo.py* |
||||
|
|
||||
\# Login to Viya using an authinfo file |
\# Login to Viya using an authinfo file |
||||
*./loginviauthinfo.py -f ~/.authinfo_geladm* |
*./loginviauthinfo.py -f ~/.authinfo_geladm* |
||||
|
|
||||
\#return all the rest calls that can be made to the folders endpoint |
\#return all the rest calls that can be made to the folders endpoint |
||||
*./callrestapi.py -e /folders -m get* |
*./callrestapi.py -e /folders -m get* |
||||
|
|
||||
\#return the json for all the folders/folders |
\#return the json for all the folders/folders |
||||
*./callrestapi.py -e /folders/folders -m get* |
*./callrestapi.py -e /folders/folders -m get* |
||||
|
|
||||
\#return simple text for all the folders/folders |
\#return simple text for all the folders/folders |
||||
*./callrestapi.py -e /folders/folders -m get -o simple* |
*./callrestapi.py -e /folders/folders -m get -o simple* |
||||
|
|
||||
\#rest calls often limit the results returned the text output will tell you returned and total available items |
\#rest calls often limit the results returned the text output will tell you returned and total available items |
||||
\#in this call set a limit above the total items to see everything |
\#in this call set a limit above the total items to see everything |
||||
*./callrestapi.py -e /folders/folders?limit=500 -m get -o simple* |
*./callrestapi.py -e /folders/folders?limit=500 -m get -o simple* |
||||
|
|
||||
|
|
||||
\#return the json for all the identities |
\#return the json for all the identities |
||||
*./callrestapi.py -e /identities/identities -m get* |
*./callrestapi.py -e /identities/identities -m get* |
||||
|
|
||||
\#return the json for all the identities output to a file |
\#return the json for all the identities output to a file |
||||
*./callrestapi.py -e /identities/identities -m get > identities.json* |
*./callrestapi.py -e /identities/identities -m get > identities.json* |
||||
|
|
||||
\#refresh the identities cache |
\#refresh the identities cache |
||||
*./callrestapi.py -e /identities/userCount -m get* |
*./callrestapi.py -e /identities/userCount -m get* |
||||
*./callrestapi.py -e /identities/cache/refreshes -m post* |
*./callrestapi.py -e /identities/cache/refreshes -m post* |
||||
|
|
||||
\# pass the folder path and return the folder id and uri |
\# pass the folder path and return the folder id and uri |
||||
*./getfolderid.py -f /gelcontent* |
*./getfolderid.py -f /gelcontent* |
||||
|
|
||||
\# delete a folder based on its path |
\# delete a folder based on its path |
||||
*./deletefolder.py -f /gelcontent* |
*./deletefolder.py -f /gelcontent* |
||||
|
|
||||
\#return a set of configuration properties |
\#return a set of configuration properties |
||||
*./getconfigurationproperties.py -c sas.identities.providers.ldap.user -o simple* |
*./getconfigurationproperties.py -c sas.identities.providers.ldap.user -o simple* |
||||
|
|
||||
\#create a domain using createdomain |
\#create a domain using createdomain |
||||
*./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HR ,Sales"* |
*./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HR ,Sales"* |
||||
|
|
||||
\#Update an existing domain to add credentials from a csv file |
\#Update an existing domain to add credentials from a csv file |
||||
*./updatedomain.py -d LASRAuth -f /tmp/myusers.csv* |
*./updatedomain.py -d LASRAuth -f /tmp/myusers.csv* |
||||
|
|
||||
csv file format |
csv file format |
||||
no header row |
no header row |
||||
column1 is userid |
column1 is userid |
||||
column2 is password |
column2 is password |
||||
column3 is identity |
column3 is identity |
||||
column4 is identity type (user or group) |
column4 is identity type (user or group) |
||||
|
|
||||
For example: |
For example: |
||||
myuserid,mypass,Sales,group |
myuserid,mypass,Sales,group |
||||
acct1,pw1,sasadm,user |
acct1,pw1,sasadm,user |
||||
|
|
||||
\#create a domain using callrestapi. Last part of endpoint is domain name |
\#create a domain using callrestapi. Last part of endpoint is domain name |
||||
*./callrestapi.py -e /credentials/domains/\<newdomain\> -m post -i domain.json* |
*./callrestapi.py -e /credentials/domains/\<newdomain\> -m post -i domain.json* |
||||
|
|
||||
INPUT JSON must be formatted as the endpoint expects. Example: |
INPUT JSON must be formatted as the endpoint expects. Example: |
||||
|
|
||||
{ |
{ |
||||
"id": "\<newdomain\>", |
"id": "\<newdomain\>", |
||||
"type": "password" |
"type": "password" |
||||
} |
} |
||||
|
|
||||
\#test folder access |
\#test folder access |
||||
*./root/admin/pyviyatools/testFolderAccess.py -f '/gelcontent' -p Sales -m read -s grant -q* |
*./root/admin/pyviyatools/testFolderAccess.py -f '/gelcontent' -p Sales -m read -s grant -q* |
||||
|
|
||||
\#return basic content using accept response type |
\#return basic content using accept response type |
||||
*./callrestapi.py -m get -e /identities/users/sasadm -a "application/vnd.sas.identity.basic+json"* |
*./callrestapi.py -m get -e /identities/users/sasadm -a "application/vnd.sas.identity.basic+json"* |
||||
|
|
||||
\# Display all sasadministrator rules |
\# Display all sasadministrator rules |
||||
*./listrules.py --p SASadministrators -o simple* |
*./listrules.py --p SASadministrators -o simple* |
||||
|
|
||||
\# Display all rules that contain SASVisual in the URI |
\# Display all rules that contain SASVisual in the URI |
||||
*./listrules.py -u SASVisual -o simple* |
*./listrules.py -u SASVisual -o simple* |
||||
|
|
||||
\# Create folders from a CSV file |
\# Create folders from a CSV file |
||||
*./createfolders.py" -f /tmp/newfolders.csv* |
*./createfolders.py" -f /tmp/newfolders.csv* |
||||
|
|
||||
FORMAT OF CSV file folder path (parents must exist), description |
FORMAT OF CSV file folder path (parents must exist), description |
||||
/RnD, Folder under root for R&D |
/RnD, Folder under root for R&D |
||||
/RnD/reports, reports |
/RnD/reports, reports |
||||
/RnD/analysis, analysis |
/RnD/analysis, analysis |
||||
/RnD/data plans, data plans |
/RnD/data plans, data plans |
||||
/temp,My temporary folder |
/temp,My temporary folder |
||||
/temp/mystuff, sub-folder |
/temp/mystuff, sub-folder |
||||
|
|
||||
\# Update the theme for the user sasadm |
\# Update the theme for the user sasadm |
||||
*./updatepreferences.py -t user -tn sasadm -pi OpenUI.Theme.Default -pv sas_hcb* |
*./updatepreferences.py -t user -tn sasadm -pi OpenUI.Theme.Default -pv sas_hcb* |
||||
|
|
||||
|
|
||||
\#Explain direct and indirect permissions on the folder /folderA/folderB, no header row. For folders, conveyed permissions are shown by default. |
\#Explain direct and indirect permissions on the folder /folderA/folderB, no header row. For folders, conveyed permissions are shown by default. |
||||
*./explainaccess.py -f /folderA/folderB* |
*./explainaccess.py -f /folderA/folderB* |
||||
|
|
||||
\#As above but for a specific user named Heather |
\#As above but for a specific user named Heather |
||||
*./explainaccess.py -f /folderA/folderB -n Heather -t user* |
*./explainaccess.py -f /folderA/folderB -n Heather -t user* |
||||
|
|
||||
\#As above with a header row |
\#As above with a header row |
||||
*./explainaccess.py -f /folderA/folderB --header* |
*./explainaccess.py -f /folderA/folderB --header* |
||||
|
|
||||
\#As above with a header row and the folder path, which is useful if you concatenate sets of results in one file |
\#As above with a header row and the folder path, which is useful if you concatenate sets of results in one file |
||||
*./explainaccess.py -f /folderA/folderB -p --header* |
*./explainaccess.py -f /folderA/folderB -p --header* |
||||
|
|
||||
\#As above showing only rows which include a direct grant or prohibit |
\#As above showing only rows which include a direct grant or prohibit |
||||
*./explainaccess.py -f /folderA/folderB --direct_only* |
*./explainaccess.py -f /folderA/folderB --direct_only* |
||||
|
|
||||
\#Explain direct and indirect permissions on a service endpoint. Note in the results that there are no conveyed permissions. By default they are not shown for URIs. |
\#Explain direct and indirect permissions on a service endpoint. Note in the results that there are no conveyed permissions. By default they are not shown for URIs. |
||||
*./explainaccess.py -u /SASEnvironmentManager/dashboard* |
*./explainaccess.py -u /SASEnvironmentManager/dashboard* |
||||
|
|
||||
\#As above but including a header row and the create permission, which is relevant for services but not for folders and other objects |
\#As above but including a header row and the create permission, which is relevant for services but not for folders and other objects |
||||
*./explainaccess.py -u /SASEnvironmentManager/dashboard --header -l read update delete secure add remove create* |
*./explainaccess.py -u /SASEnvironmentManager/dashboard --header -l read update delete secure add remove create* |
||||
|
|
||||
\#Explain direct and indirect permissions on a report, reducing the permissions reported to just read, update, delete and secure, since none of add, remove or create are applicable to a report. |
\#Explain direct and indirect permissions on a report, reducing the permissions reported to just read, update, delete and secure, since none of add, remove or create are applicable to a report. |
||||
*./explainaccess.py -u /reports/reports/*folder_id *--header -l read update delete secure* |
*./explainaccess.py -u /reports/reports/*folder_id *--header -l read update delete secure* |
||||
|
|
||||
\#Explain direct and indirect permissions on a folder expressed as a URI. Keep the default permissions list, but for completeness we must also specify -c true to request conveyed permissions be displayed, as they are not displayed by default for URIs. |
\#Explain direct and indirect permissions on a folder expressed as a URI. Keep the default permissions list, but for completeness we must also specify -c true to request conveyed permissions be displayed, as they are not displayed by default for URIs. |
||||
*./explainaccess.py -u /folders/folders/*folder_id *--header -p -c true* |
*./explainaccess.py -u /folders/folders/*folder_id *--header -p -c true* |
||||
|
|
||||
**Troubleshooting** |
**Troubleshooting** |
||||
|
|
||||
The most common problem is an expired access token. You may see a message like: |
The most common problem is an expired access token. You may see a message like: |
||||
|
|
||||
{"errorCode":0,"message":"Cannot convert access token to JSON","details":["traceId: 6bca23b2b3a2cfda","path: /folders/folders"],"remediation":null,"links":[ ],"version":2,"httpStatusCode":401} |
{"errorCode":0,"message":"Cannot convert access token to JSON","details":["traceId: 6bca23b2b3a2cfda","path: /folders/folders"],"remediation":null,"links":[ ],"version":2,"httpStatusCode":401} |
||||
|
|
||||
To fix the problem generate a new access token /opt/sas/viya/home/bin/sas-admin auth login |
To fix the problem generate a new access token /opt/sas/viya/home/bin/sas-admin auth login |
||||
|
|
||||
To see the current setup, including python and package versions, environment variable settings, profile information and current user. Run |
To see the current setup, including python and package versions, environment variable settings, profile information and current user. Run |
||||
|
|
||||
*python showsetup.py* |
*python showsetup.py* |
||||
|
|
||||
If you get this error : Login failed. Error with security certificate. |
If you get this error : Login failed. Error with security certificate. |
||||
|
|
||||
Set the environment variable for the SSL certificate file. For example: |
Set the environment variable for the SSL certificate file. For example: |
||||
export SSL_CERT_FILE=/opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.pem |
export SSL_CERT_FILE=/opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.pem |
||||
|
|
||||
|
|
||||
If you get this error: |
If you get this error: |
||||
Raise SSLError(e, request=request) |
Raise SSLError(e, request=request) |
||||
requests.exceptions.SSLError: HTTPSConnectionPool(host='intviya01.race.sas.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:579)'),)) |
requests.exceptions.SSLError: HTTPSConnectionPool(host='intviya01.race.sas.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:579)'),)) |
||||
|
|
||||
Set the environment variable for the SSL certificate file. For example: |
Set the environment variable for the SSL certificate file. For example: |
||||
export REQUESTS_CA_BUNDLE=/opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.pem |
export REQUESTS_CA_BUNDLE=/opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.pem |
||||
|
|
||||
|
|
||||
## Developing with the existing functions |
## Developing with the existing functions |
||||
|
|
||||
The file sharedfunctions.py contains a set of generic functions that make it easy to build additional tools. |
The file sharedfunctions.py contains a set of generic functions that make it easy to build additional tools. |
||||
|
|
||||
*callrestapi* is the main function, called by many other programs and by the callrestapi program to make the REST calls. It accepts as parameters: |
*callrestapi* is the main function, called by many other programs and by the callrestapi program to make the REST calls. It accepts as parameters: |
||||
|
|
||||
* reqval: the request value which is the rest endpoint for the request |
* reqval: the request value which is the rest endpoint for the request |
||||
* reqtype: the type of REST request, get,put, post, delete |
* reqtype: the type of REST request, get,put, post, delete |
||||
* acceptType: optinal accept type content header |
* acceptType: optinal accept type content header |
||||
* contentType: optional content type content header |
* contentType: optional content type content header |
||||
* data: optionally a python dictionary created from the json for the rest request |
* data: optionally a python dictionary created from the json for the rest request |
||||
* stoponerror: whether the function will stop all further processing if an error occurs (default 0 to not stop) |
* stoponerror: whether the function will stop all further processing if an error occurs (default 0 to not stop) |
||||
|
|
||||
|
|
||||
## Contributing |
## Contributing |
||||
|
|
||||
We welcome your contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to submit contributions to this project. |
We welcome your contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to submit contributions to this project. |
||||
|
|
||||
## License |
## License |
||||
|
|
||||
This project is licensed under the [Apache 2.0 License](LICENSE). |
This project is licensed under the [Apache 2.0 License](LICENSE). |
||||
|
|
||||
|
|||||
@ -1,93 +1,93 @@ |
|||||
#!/usr/bin/python |
#!/usr/bin/python |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# |
# |
||||
# createfolders.py |
# createfolders.py |
||||
# October 2018 |
# October 2018 |
||||
# |
# |
||||
# |
# |
||||
# Change History |
# Change History |
||||
# |
# |
||||
# 30oct2018 Initial development |
# 30oct2018 Initial development |
||||
# |
# |
||||
# Format of csv file is two columns |
# Format of csv file is two columns |
||||
# Column 1 is the full path to the folder |
# Column 1 is the full path to the folder |
||||
# Column 2 is a description |
# Column 2 is a description |
||||
# |
# |
||||
# For example: |
# For example: |
||||
#/RnD, Folder under root for R&D |
#/RnD, Folder under root for R&D |
||||
#/RnD/reports, reports |
#/RnD/reports, reports |
||||
#/RnD/analysis, analysis |
#/RnD/analysis, analysis |
||||
#/RnD/data plans, data plans |
#/RnD/data plans, data plans |
||||
#/temp,My temporary folder |
#/temp,My temporary folder |
||||
|
|
||||
# |
# |
||||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
# Licensed under the Apache License, Version 2.0 (the License); |
# Licensed under the Apache License, Version 2.0 (the License); |
||||
# you may not use this file except in compliance with the License. |
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
# You may obtain a copy of the License at |
||||
# |
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
# Unless required by applicable law or agreed to in writing, software |
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
# limitations under the License. |
||||
# |
# |
||||
import argparse |
import argparse |
||||
import csv |
import csv |
||||
import os |
import os |
||||
from sharedfunctions import callrestapi, getfolderid, file_accessible |
from sharedfunctions import callrestapi, getfolderid, file_accessible |
||||
|
|
||||
# setup command-line arguements |
# setup command-line arguements |
||||
parser = argparse.ArgumentParser(description="Create folders that are read from a csv file") |
parser = argparse.ArgumentParser(description="Create folders that are read from a csv file") |
||||
parser.add_argument("-f","--file", help="Full path to csv file containing folders, format of csv: 'folderpath,description ",required='True') |
parser.add_argument("-f","--file", help="Full path to csv file containing folders, format of csv: 'folderpath,description ",required='True') |
||||
args = parser.parse_args() |
args = parser.parse_args() |
||||
file=args.file |
file=args.file |
||||
|
|
||||
reqtype="post" |
reqtype="post" |
||||
|
|
||||
check=file_accessible(file,'r') |
check=file_accessible(file,'r') |
||||
|
|
||||
# file can be read |
# file can be read |
||||
if check: |
if check: |
||||
|
|
||||
with open(file, 'rt') as f: |
with open(file, 'rt') as f: |
||||
|
|
||||
filecontents = csv.reader(f) |
filecontents = csv.reader(f) |
||||
for row in filecontents: |
for row in filecontents: |
||||
|
|
||||
#print(row) |
#print(row) |
||||
newfolder=row[0] |
newfolder=row[0] |
||||
description=row[1] |
description=row[1] |
||||
|
|
||||
|
|
||||
if newfolder[0]!='/': newfolder="/"+newfolder |
if newfolder[0]!='/': newfolder="/"+newfolder |
||||
|
|
||||
folder=os.path.basename(os.path.normpath(newfolder)) |
folder=os.path.basename(os.path.normpath(newfolder)) |
||||
parent_folder=os.path.dirname(newfolder) |
parent_folder=os.path.dirname(newfolder) |
||||
|
|
||||
data = {} |
data = {} |
||||
data['name'] = folder |
data['name'] = folder |
||||
data['description'] = description |
data['description'] = description |
||||
|
|
||||
|
|
||||
print ("Creating folder "+newfolder ) |
print ("Creating folder "+newfolder ) |
||||
|
|
||||
if parent_folder=="/": reqval='/folders/folders' |
if parent_folder=="/": reqval='/folders/folders' |
||||
else: # parent folder create a child |
else: # parent folder create a child |
||||
|
|
||||
parentinfo=getfolderid(parent_folder) |
parentinfo=getfolderid(parent_folder) |
||||
|
|
||||
if parentinfo != None: |
if parentinfo != None: |
||||
|
|
||||
parenturi=parentinfo[1] |
parenturi=parentinfo[1] |
||||
reqval='/folders/folders?parentFolderUri='+parenturi |
reqval='/folders/folders?parentFolderUri='+parenturi |
||||
|
|
||||
else: print("Parent folder not found") |
else: print("Parent folder not found") |
||||
|
|
||||
myresult=callrestapi(reqval,reqtype,data=data,stoponerror=0) |
myresult=callrestapi(reqval,reqtype,data=data,stoponerror=0) |
||||
else: |
else: |
||||
print("ERROR: cannot read "+file) |
print("ERROR: cannot read "+file) |
||||
|
|
||||
@ -1,293 +1,293 @@ |
|||||
#!/usr/bin/python |
#!/usr/bin/python |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# |
# |
||||
# explainaccess.py |
# explainaccess.py |
||||
# November 2018 |
# November 2018 |
||||
# |
# |
||||
# Usage: |
# Usage: |
||||
# explainaccess.py [-f folderpath | -u objectURI] [-n name_of_user_or_group -t user|group] [-p] [--header] [--direct_only] [-l permissions_list] [-c true|false] [-d] |
# explainaccess.py [-f folderpath | -u objectURI] [-n name_of_user_or_group -t user|group] [-p] [--header] [--direct_only] [-l permissions_list] [-c true|false] [-d] |
||||
# |
# |
||||
# Examples: |
# Examples: |
||||
# |
# |
||||
# 1. Explain direct and indirect permissions on the folder /folderA/folderB, no header row. For folders, conveyed permissions are shown by default. |
# 1. Explain direct and indirect permissions on the folder /folderA/folderB, no header row. For folders, conveyed permissions are shown by default. |
||||
# ./explainaccess.py -f /folderA/folderB |
# ./explainaccess.py -f /folderA/folderB |
||||
# |
# |
||||
# 2. As 1. but for a specific user named Heather |
# 2. As 1. but for a specific user named Heather |
||||
# ./explainaccess.py -f /folderA/folderB -n Heather -t user |
# ./explainaccess.py -f /folderA/folderB -n Heather -t user |
||||
# |
# |
||||
# 3. As 1. with a header row |
# 3. As 1. with a header row |
||||
# ./explainaccess.py -f /folderA/folderB --header |
# ./explainaccess.py -f /folderA/folderB --header |
||||
# |
# |
||||
# 4. As 1. with a header row and the folder path, which is useful if you concatenate sets of results in one file |
# 4. As 1. with a header row and the folder path, which is useful if you concatenate sets of results in one file |
||||
# ./explainaccess.py -f /folderA/folderB -p --header |
# ./explainaccess.py -f /folderA/folderB -p --header |
||||
# |
# |
||||
# 5. As 1. showing only rows which include a direct grant or prohibit |
# 5. As 1. showing only rows which include a direct grant or prohibit |
||||
# ./explainaccess.py -f /folderA/folderB --direct_only |
# ./explainaccess.py -f /folderA/folderB --direct_only |
||||
# |
# |
||||
# 6. Explain direct and indirect permissions on a service endpoint. Note in the results that there are no conveyed permissions. |
# 6. Explain direct and indirect permissions on a service endpoint. Note in the results that there are no conveyed permissions. |
||||
# By default they are not shown for URIs. |
# By default they are not shown for URIs. |
||||
# ./explainaccess.py -u /SASEnvironmentManager/dashboard |
# ./explainaccess.py -u /SASEnvironmentManager/dashboard |
||||
# |
# |
||||
# 7. As 6. but including a header row and the create permission, which is relevant for services but not for folders and other objects |
# 7. As 6. but including a header row and the create permission, which is relevant for services but not for folders and other objects |
||||
# ./explainaccess.py -u /SASEnvironmentManager/dashboard --header -l read update delete secure add remove create |
# ./explainaccess.py -u /SASEnvironmentManager/dashboard --header -l read update delete secure add remove create |
||||
# |
# |
||||
# 8. Explain direct and indirect permissions on a report, reducing the permissions reported to just read, update, delete and secure, |
# 8. Explain direct and indirect permissions on a report, reducing the permissions reported to just read, update, delete and secure, |
||||
# since none of add, remove or create are applicable to a report. |
# since none of add, remove or create are applicable to a report. |
||||
# ./explainaccess.py -u /reports/reports/e2e0e601-b5a9-4601-829a-c5137f7441c6 --header -l read update delete secure |
# ./explainaccess.py -u /reports/reports/e2e0e601-b5a9-4601-829a-c5137f7441c6 --header -l read update delete secure |
||||
# |
# |
||||
# 9. Explain direct and indirect permissions on a folder expressed as a URI. Keep the default permissions list, but for completeness |
# 9. Explain direct and indirect permissions on a folder expressed as a URI. Keep the default permissions list, but for completeness |
||||
# we must also specify -c true to request conveyed permissions be displayed, as they are not displayed by default for URIs. |
# we must also specify -c true to request conveyed permissions be displayed, as they are not displayed by default for URIs. |
||||
# ./explainaccess.py -u /folders/folders/9145d26a-2c0d-4523-8835-ad186bb57fa6 --header -p -c true |
# ./explainaccess.py -u /folders/folders/9145d26a-2c0d-4523-8835-ad186bb57fa6 --header -p -c true |
||||
# |
# |
||||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
# Licensed under the Apache License, Version 2.0 (the License); |
# Licensed under the Apache License, Version 2.0 (the License); |
||||
# you may not use this file except in compliance with the License. |
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
# You may obtain a copy of the License at |
||||
# |
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
# Unless required by applicable law or agreed to in writing, software |
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
# limitations under the License. |
||||
# |
# |
||||
|
|
||||
|
|
||||
clidir='/opt/sas/viya/home/bin/' |
clidir='/opt/sas/viya/home/bin/' |
||||
debug=False |
debug=False |
||||
direct_only=False |
direct_only=False |
||||
valid_permissions=['read','update','delete','secure','add','remove','create'] |
valid_permissions=['read','update','delete','secure','add','remove','create'] |
||||
default_permissions=['read','update','delete','secure','add','remove'] |
default_permissions=['read','update','delete','secure','add','remove'] |
||||
#direct_permission_suffix=u"\u2666" #Black diamond suit symbol - ok in stdout, seems to cause problems with other tools |
#direct_permission_suffix=u"\u2666" #Black diamond suit symbol - ok in stdout, seems to cause problems with other tools |
||||
direct_permission_suffix='*' |
direct_permission_suffix='*' |
||||
|
|
||||
|
|
||||
# Import Python modules |
# Import Python modules |
||||
|
|
||||
import argparse |
import argparse |
||||
import subprocess |
import subprocess |
||||
import json |
import json |
||||
import sys |
import sys |
||||
|
|
||||
from sharedfunctions import getfolderid,callrestapi |
from sharedfunctions import getfolderid,callrestapi |
||||
|
|
||||
# Define exception handler so that we only output trace info from errors when in debug mode |
# Define exception handler so that we only output trace info from errors when in debug mode |
||||
def exception_handler(exception_type, exception, traceback, debug_hook=sys.excepthook): |
def exception_handler(exception_type, exception, traceback, debug_hook=sys.excepthook): |
||||
if debug: |
if debug: |
||||
debug_hook(exception_type, exception, traceback) |
debug_hook(exception_type, exception, traceback) |
||||
else: |
else: |
||||
print "%s: %s" % (exception_type.__name__, exception) |
print "%s: %s" % (exception_type.__name__, exception) |
||||
|
|
||||
sys.excepthook = exception_handler |
sys.excepthook = exception_handler |
||||
|
|
||||
parser = argparse.ArgumentParser() |
parser = argparse.ArgumentParser() |
||||
parser.add_argument("-f","--folderpath", help="Path to a Viya folder. You must specify either -f folderpath or -u objectURI.") |
parser.add_argument("-f","--folderpath", help="Path to a Viya folder. You must specify either -f folderpath or -u objectURI.") |
||||
parser.add_argument("-u","--objecturi", help="Object URI. You must specify either -f folderpath or -u objectURI.") |
parser.add_argument("-u","--objecturi", help="Object URI. You must specify either -f folderpath or -u objectURI.") |
||||
parser.add_argument("-n","--name", help="Enter the name of the user or group to test.") |
parser.add_argument("-n","--name", help="Enter the name of the user or group to test.") |
||||
parser.add_argument("-t","--principaltype", help="Enter the type of principal to test: user or group.",choices=['user','group']) |
parser.add_argument("-t","--principaltype", help="Enter the type of principal to test: user or group.",choices=['user','group']) |
||||
parser.add_argument("-p","--printpath", action='store_true', help="Print the folder path in each row") |
parser.add_argument("-p","--printpath", action='store_true', help="Print the folder path in each row") |
||||
parser.add_argument("--header", action='store_true', help="Print a header row") |
parser.add_argument("--header", action='store_true', help="Print a header row") |
||||
parser.add_argument("--direct_only", action='store_true', help="Show only explanations which include a direct grant or prohibit") |
parser.add_argument("--direct_only", action='store_true', help="Show only explanations which include a direct grant or prohibit") |
||||
parser.add_argument("-l","--permissions_list", nargs="+", help="List of permissions, to include instead of all seven by default", default=default_permissions) |
parser.add_argument("-l","--permissions_list", nargs="+", help="List of permissions, to include instead of all seven by default", default=default_permissions) |
||||
parser.add_argument("-c","--convey", help="Show conveyed permissions in results. True by default when folder path is specified. False by dfefault if Object URI is specified.",choices=['true','false']) |
parser.add_argument("-c","--convey", help="Show conveyed permissions in results. True by default when folder path is specified. False by dfefault if Object URI is specified.",choices=['true','false']) |
||||
parser.add_argument("-d","--debug", action='store_true', help="Debug") |
parser.add_argument("-d","--debug", action='store_true', help="Debug") |
||||
args = parser.parse_args() |
args = parser.parse_args() |
||||
path_to_folder=args.folderpath |
path_to_folder=args.folderpath |
||||
objecturi=args.objecturi |
objecturi=args.objecturi |
||||
name=args.name |
name=args.name |
||||
principaltype=args.principaltype |
principaltype=args.principaltype |
||||
printpath=args.printpath |
printpath=args.printpath |
||||
header=args.header |
header=args.header |
||||
direct_only=args.direct_only |
direct_only=args.direct_only |
||||
permissions=args.permissions_list |
permissions=args.permissions_list |
||||
conveyparam=args.convey |
conveyparam=args.convey |
||||
debug=args.debug |
debug=args.debug |
||||
|
|
||||
if path_to_folder and objecturi: |
if path_to_folder and objecturi: |
||||
raise Exception('You must specify either -f and a Viya folder path, or -u and an object URI, but not both.') |
raise Exception('You must specify either -f and a Viya folder path, or -u and an object URI, but not both.') |
||||
if path_to_folder is None and objecturi is None: |
if path_to_folder is None and objecturi is None: |
||||
raise Exception('You must specify either -f and a Viya folder path, or -u and an object URI. You may not specify both.') |
raise Exception('You must specify either -f and a Viya folder path, or -u and an object URI. You may not specify both.') |
||||
|
|
||||
if name and principaltype is None: |
if name and principaltype is None: |
||||
raise Exception('If you specify a principal name, you must also specify a principal type which can be user or group.') |
raise Exception('If you specify a principal name, you must also specify a principal type which can be user or group.') |
||||
if principaltype and name is None: |
if principaltype and name is None: |
||||
raise Exception('If you specify a principal type, you must also specify a principal name.') |
raise Exception('If you specify a principal type, you must also specify a principal name.') |
||||
|
|
||||
for permission in permissions: |
for permission in permissions: |
||||
if permission not in valid_permissions: |
if permission not in valid_permissions: |
||||
raise Exception(permission+' is not the name of a permission. Valid permissions are: '+' '.join(map(str, valid_permissions))) |
raise Exception(permission+' is not the name of a permission. Valid permissions are: '+' '.join(map(str, valid_permissions))) |
||||
|
|
||||
# Two ways this program can be used: for a folder, or for a URI. |
# Two ways this program can be used: for a folder, or for a URI. |
||||
if path_to_folder: |
if path_to_folder: |
||||
getfolderid_result_json=getfolderid(path_to_folder) |
getfolderid_result_json=getfolderid(path_to_folder) |
||||
|
|
||||
if (debug): |
if (debug): |
||||
print(getfolderid_result_json) |
print(getfolderid_result_json) |
||||
|
|
||||
|
|
||||
if getfolderid_result_json[0] is not None: |
if getfolderid_result_json[0] is not None: |
||||
folder_uri=getfolderid_result_json[1] |
folder_uri=getfolderid_result_json[1] |
||||
if (debug): |
if (debug): |
||||
print("Id = "+getfolderid_result_json[0]) |
print("Id = "+getfolderid_result_json[0]) |
||||
print("URI = "+folder_uri) |
print("URI = "+folder_uri) |
||||
print("Path = "+getfolderid_result_json[2]) |
print("Path = "+getfolderid_result_json[2]) |
||||
|
|
||||
explainuri=folder_uri |
explainuri=folder_uri |
||||
resultpath=path_to_folder |
resultpath=path_to_folder |
||||
#Set convey to true, unless user overrode that setting and asked for false |
#Set convey to true, unless user overrode that setting and asked for false |
||||
if(conveyparam is not None and conveyparam.lower()=='false'): |
if(conveyparam is not None and conveyparam.lower()=='false'): |
||||
convey=False |
convey=False |
||||
else: |
else: |
||||
convey=True |
convey=True |
||||
|
|
||||
else: |
else: |
||||
explainuri=objecturi |
explainuri=objecturi |
||||
# This tool explains the permissions of any object. |
# This tool explains the permissions of any object. |
||||
# If the object is a folder, we expect the user to supply path_to_folder, and we find its ID |
# If the object is a folder, we expect the user to supply path_to_folder, and we find its ID |
||||
# If the object is something else, we don't have the path to the object. |
# If the object is something else, we don't have the path to the object. |
||||
# It might be possible to get the path to the object from it's ID, but I'm not sure if there is a universal way to do that. |
# It might be possible to get the path to the object from it's ID, but I'm not sure if there is a universal way to do that. |
||||
# If the object is a report, you can call e.g. |
# If the object is a report, you can call e.g. |
||||
# /opt/sas/viya/home/bin/sas-admin --output text reports show-info -id 43de1f98-d7ef-4490-bb46-cc177f995052 |
# /opt/sas/viya/home/bin/sas-admin --output text reports show-info -id 43de1f98-d7ef-4490-bb46-cc177f995052 |
||||
# And the folder is one of the results passed back. But that call uses the reports plug-in to sas-admin and |
# And the folder is one of the results passed back. But that call uses the reports plug-in to sas-admin and |
||||
# should not be expected to return the path to other objects. |
# should not be expected to return the path to other objects. |
||||
# Plus, some objects do not have a path: service endpoints, for example. |
# Plus, some objects do not have a path: service endpoints, for example. |
||||
# This is a possible area for future improvement. |
# This is a possible area for future improvement. |
||||
resultpath=objecturi |
resultpath=objecturi |
||||
#Set convey to false, unless user overrode that setting and asked for true |
#Set convey to false, unless user overrode that setting and asked for true |
||||
if(conveyparam is not None and conveyparam.lower()=='true'): |
if(conveyparam is not None and conveyparam.lower()=='true'): |
||||
convey=True |
convey=True |
||||
else: |
else: |
||||
convey=False |
convey=False |
||||
|
|
||||
|
|
||||
#Use the /authorization/decision endpoint to ask for an explanation of the rules that are relevant to principals on this URI |
#Use the /authorization/decision endpoint to ask for an explanation of the rules that are relevant to principals on this URI |
||||
#See Authorization API documentation in swagger at http://swagger.na.sas.com/apis/authorization/v4/apidoc.html#op:createExplanation |
#See Authorization API documentation in swagger at http://swagger.na.sas.com/apis/authorization/v4/apidoc.html#op:createExplanation |
||||
endpoint='/authorization/decision' |
endpoint='/authorization/decision' |
||||
if name and principaltype: |
if name and principaltype: |
||||
if(principaltype.lower()=='user'): |
if(principaltype.lower()=='user'): |
||||
endpoint=endpoint+'?additionalUser='+name |
endpoint=endpoint+'?additionalUser='+name |
||||
else: |
else: |
||||
endpoint=endpoint+'?additionalGroup='+name |
endpoint=endpoint+'?additionalGroup='+name |
||||
method='post' |
method='post' |
||||
accept='application/vnd.sas.authorization.explanations+json' |
accept='application/vnd.sas.authorization.explanations+json' |
||||
content='application/vnd.sas.selection+json' |
content='application/vnd.sas.selection+json' |
||||
inputdata={"resources":[explainuri]} |
inputdata={"resources":[explainuri]} |
||||
|
|
||||
decisions_result_json=callrestapi(endpoint,method,accept,content,inputdata) |
decisions_result_json=callrestapi(endpoint,method,accept,content,inputdata) |
||||
|
|
||||
#print(decisions_result_json) |
#print(decisions_result_json) |
||||
#print('decisions_result_json is a '+type(decisions_result_json).__name__+' object') #decisions_result_json is a dict object |
#print('decisions_result_json is a '+type(decisions_result_json).__name__+' object') #decisions_result_json is a dict object |
||||
e = decisions_result_json['explanations'][explainuri] |
e = decisions_result_json['explanations'][explainuri] |
||||
|
|
||||
#print('e is a '+type(e).__name__+' object') #e is a list object |
#print('e is a '+type(e).__name__+' object') #e is a list object |
||||
|
|
||||
# Print header row if header argument was specified |
# Print header row if header argument was specified |
||||
if header: |
if header: |
||||
if printpath: |
if printpath: |
||||
if convey: |
if convey: |
||||
print('path,principal,'+','.join(map(str, permissions))+','+','.join(map('{0}(convey)'.format, permissions))) |
print('path,principal,'+','.join(map(str, permissions))+','+','.join(map('{0}(convey)'.format, permissions))) |
||||
else: |
else: |
||||
print('path,principal,'+','.join(map(str, permissions))) |
print('path,principal,'+','.join(map(str, permissions))) |
||||
else: |
else: |
||||
if convey: |
if convey: |
||||
print('principal,'+','.join(map(str, permissions))+','+','.join(map('{0}(convey)'.format, permissions))) |
print('principal,'+','.join(map(str, permissions))+','+','.join(map('{0}(convey)'.format, permissions))) |
||||
else: |
else: |
||||
print('principal,'+','.join(map(str, permissions))) |
print('principal,'+','.join(map(str, permissions))) |
||||
|
|
||||
principal_found=False |
principal_found=False |
||||
|
|
||||
#For each principle's section in the explanations section of the data returned from the REST API call... |
#For each principle's section in the explanations section of the data returned from the REST API call... |
||||
for pi in e: |
for pi in e: |
||||
#print pi['principal'] |
#print pi['principal'] |
||||
#We are starting a new principal, so initialise some variables for this principal |
#We are starting a new principal, so initialise some variables for this principal |
||||
outstr='' |
outstr='' |
||||
has_a_direct_grant_or_deny=False |
has_a_direct_grant_or_deny=False |
||||
if printpath: |
if printpath: |
||||
outstr=outstr+resultpath+',' |
outstr=outstr+resultpath+',' |
||||
# If a name and principaltype are provided as arguments, we will only output a row for that principal |
# If a name and principaltype are provided as arguments, we will only output a row for that principal |
||||
if name and principaltype: |
if name and principaltype: |
||||
if 'name' in pi['principal']: |
if 'name' in pi['principal']: |
||||
if (pi['principal']['name'].lower() == name.lower()): |
if (pi['principal']['name'].lower() == name.lower()): |
||||
principal_found=True |
principal_found=True |
||||
outstr=outstr+pi['principal']['name'] |
outstr=outstr+pi['principal']['name'] |
||||
# Permissions on object |
# Permissions on object |
||||
for permission in permissions: |
for permission in permissions: |
||||
# Not all objects have all the permissions |
# Not all objects have all the permissions |
||||
# Note that some objects do have permissions which are not meaningful for that object. |
# Note that some objects do have permissions which are not meaningful for that object. |
||||
# E.g. SASAdministrators are granted Add and Remove on reports, by an OOTB rule which grants SASAdministrators all permissions (including Add and Remove) on /**. |
# E.g. SASAdministrators are granted Add and Remove on reports, by an OOTB rule which grants SASAdministrators all permissions (including Add and Remove) on /**. |
||||
# Meanwhile, Add and Remove are not shown in the View or Edit Authotizations dialogs for reports in EV etc. |
# Meanwhile, Add and Remove are not shown in the View or Edit Authotizations dialogs for reports in EV etc. |
||||
# So, while it may be correct for the /authorization/decisions endpoint to explain that SASAdministrators are granted Add and Remove on a report, |
# So, while it may be correct for the /authorization/decisions endpoint to explain that SASAdministrators are granted Add and Remove on a report, |
||||
# that does not alter the fact that in the context of a report, Add and Remove permissions are not meaningful. |
# that does not alter the fact that in the context of a report, Add and Remove permissions are not meaningful. |
||||
if pi[permission.lower()]: |
if pi[permission.lower()]: |
||||
# This permission was in the expanation for this principal |
# This permission was in the expanation for this principal |
||||
outstr=outstr+','+pi[permission.lower()]['result'] |
outstr=outstr+','+pi[permission.lower()]['result'] |
||||
if 'grantFactor' in pi[permission.lower()]: |
if 'grantFactor' in pi[permission.lower()]: |
||||
if 'direct' in pi[permission.lower()]['grantFactor']: |
if 'direct' in pi[permission.lower()]['grantFactor']: |
||||
if pi[permission.lower()]['grantFactor']['direct']: |
if pi[permission.lower()]['grantFactor']['direct']: |
||||
has_a_direct_grant_or_deny=True |
has_a_direct_grant_or_deny=True |
||||
outstr=outstr+direct_permission_suffix |
outstr=outstr+direct_permission_suffix |
||||
else: |
else: |
||||
# This permission was absent from the expanation for this principal |
# This permission was absent from the expanation for this principal |
||||
outstr=outstr+',' |
outstr=outstr+',' |
||||
# Conveyed permissions |
# Conveyed permissions |
||||
if convey: |
if convey: |
||||
for permission in permissions: |
for permission in permissions: |
||||
# Only a few objects have conveyed permissions at all |
# Only a few objects have conveyed permissions at all |
||||
if 'conveyedExplanation' in pi[permission.lower()]: |
if 'conveyedExplanation' in pi[permission.lower()]: |
||||
# This permission was in the expanation for this principal |
# This permission was in the expanation for this principal |
||||
outstr=outstr+','+pi[permission.lower()]['conveyedExplanation']['result'] |
outstr=outstr+','+pi[permission.lower()]['conveyedExplanation']['result'] |
||||
if 'grantFactor' in pi[permission.lower()]['conveyedExplanation']: |
if 'grantFactor' in pi[permission.lower()]['conveyedExplanation']: |
||||
if 'direct' in pi[permission.lower()]['conveyedExplanation']['grantFactor']: |
if 'direct' in pi[permission.lower()]['conveyedExplanation']['grantFactor']: |
||||
if pi[permission.lower()]['conveyedExplanation']['grantFactor']['direct']: |
if pi[permission.lower()]['conveyedExplanation']['grantFactor']['direct']: |
||||
has_a_direct_grant_or_deny=True |
has_a_direct_grant_or_deny=True |
||||
outstr=outstr+direct_permission_suffix |
outstr=outstr+direct_permission_suffix |
||||
else: |
else: |
||||
# This permission was absent from the expanation for this principal |
# This permission was absent from the expanation for this principal |
||||
outstr=outstr+',' |
outstr=outstr+',' |
||||
if direct_only: |
if direct_only: |
||||
if has_a_direct_grant_or_deny: |
if has_a_direct_grant_or_deny: |
||||
print(outstr) |
print(outstr) |
||||
else: |
else: |
||||
print(outstr) |
print(outstr) |
||||
# But if no name or principaltype are provided, we output all rows |
# But if no name or principaltype are provided, we output all rows |
||||
else: |
else: |
||||
if 'name' in pi['principal']: |
if 'name' in pi['principal']: |
||||
outstr=outstr+pi['principal']['name'] |
outstr=outstr+pi['principal']['name'] |
||||
else: |
else: |
||||
outstr=outstr+pi['principal']['type'] |
outstr=outstr+pi['principal']['type'] |
||||
# Permissions on object |
# Permissions on object |
||||
for permission in permissions: |
for permission in permissions: |
||||
# Not all objects have all the permissions |
# Not all objects have all the permissions |
||||
if pi[permission.lower()]: |
if pi[permission.lower()]: |
||||
# This permission was in the expanation for this principal |
# This permission was in the expanation for this principal |
||||
outstr=outstr+','+pi[permission.lower()]['result'] |
outstr=outstr+','+pi[permission.lower()]['result'] |
||||
if 'grantFactor' in pi[permission.lower()]: |
if 'grantFactor' in pi[permission.lower()]: |
||||
if 'direct' in pi[permission.lower()]['grantFactor']: |
if 'direct' in pi[permission.lower()]['grantFactor']: |
||||
if pi[permission.lower()]['grantFactor']['direct']: |
if pi[permission.lower()]['grantFactor']['direct']: |
||||
has_a_direct_grant_or_deny=True |
has_a_direct_grant_or_deny=True |
||||
outstr=outstr+direct_permission_suffix |
outstr=outstr+direct_permission_suffix |
||||
else: |
else: |
||||
# This permission was absent from the expanation for this principal |
# This permission was absent from the expanation for this principal |
||||
outstr=outstr+',' |
outstr=outstr+',' |
||||
# Conveyed permissions |
# Conveyed permissions |
||||
if convey: |
if convey: |
||||
for permission in permissions: |
for permission in permissions: |
||||
# Not all objects have all the permissions |
# Not all objects have all the permissions |
||||
if 'conveyedExplanation' in pi[permission.lower()]: |
if 'conveyedExplanation' in pi[permission.lower()]: |
||||
# This permission was in the expanation for this principal |
# This permission was in the expanation for this principal |
||||
outstr=outstr+','+pi[permission.lower()]['conveyedExplanation']['result'] |
outstr=outstr+','+pi[permission.lower()]['conveyedExplanation']['result'] |
||||
if 'grantFactor' in pi[permission.lower()]['conveyedExplanation']: |
if 'grantFactor' in pi[permission.lower()]['conveyedExplanation']: |
||||
if 'direct' in pi[permission.lower()]['conveyedExplanation']['grantFactor']: |
if 'direct' in pi[permission.lower()]['conveyedExplanation']['grantFactor']: |
||||
if pi[permission.lower()]['conveyedExplanation']['grantFactor']['direct']: |
if pi[permission.lower()]['conveyedExplanation']['grantFactor']['direct']: |
||||
has_a_direct_grant_or_deny=True |
has_a_direct_grant_or_deny=True |
||||
outstr=outstr+direct_permission_suffix |
outstr=outstr+direct_permission_suffix |
||||
else: |
else: |
||||
# This permission was absent from the expanation for this principal |
# This permission was absent from the expanation for this principal |
||||
outstr=outstr+',' |
outstr=outstr+',' |
||||
if direct_only: |
if direct_only: |
||||
if has_a_direct_grant_or_deny: |
if has_a_direct_grant_or_deny: |
||||
print(outstr) |
print(outstr) |
||||
else: |
else: |
||||
print(outstr) |
print(outstr) |
||||
|
|||||
@ -1,124 +1,124 @@ |
|||||
#!/usr/bin/python |
#!/usr/bin/python |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# |
# |
||||
# listrules.py |
# listrules.py |
||||
# August 2018 |
# August 2018 |
||||
# |
# |
||||
# listrulesforidentity |
# listrulesforidentity |
||||
# |
# |
||||
# Change History |
# Change History |
||||
# December 2018 - Added custom CSV output code, which writes out consistent columns in a specific order for the result rules JSON |
# December 2018 - Added custom CSV output code, which writes out consistent columns in a specific order for the result rules JSON |
||||
# |
# |
||||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
# Licensed under the Apache License, Version 2.0 (the License); |
# Licensed under the Apache License, Version 2.0 (the License); |
||||
# you may not use this file except in compliance with the License. |
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
# You may obtain a copy of the License at |
||||
# |
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
# Unless required by applicable law or agreed to in writing, software |
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
# limitations under the License. |
||||
# |
# |
||||
|
|
||||
import argparse |
import argparse |
||||
|
|
||||
from sharedfunctions import callrestapi, printresult |
from sharedfunctions import callrestapi, printresult |
||||
|
|
||||
# setup command-line arguements |
# setup command-line arguements |
||||
parser = argparse.ArgumentParser(description="List rules for a principal and/or an endpoint") |
parser = argparse.ArgumentParser(description="List rules for a principal and/or an endpoint") |
||||
|
|
||||
parser.add_argument("-u","--uri", help="Enter a string that the objecturi contains.",default="none") |
parser.add_argument("-u","--uri", help="Enter a string that the objecturi contains.",default="none") |
||||
parser.add_argument("-p","--principal", help="Enter the identity name or authenticatedUsers, everyone or guest",default='none') |
parser.add_argument("-p","--principal", help="Enter the identity name or authenticatedUsers, everyone or guest",default='none') |
||||
parser.add_argument("-o","--output", help="Output Style", choices=['csv','json','simple'],default='json') |
parser.add_argument("-o","--output", help="Output Style", choices=['csv','json','simple'],default='json') |
||||
|
|
||||
args = parser.parse_args() |
args = parser.parse_args() |
||||
objuri=args.uri |
objuri=args.uri |
||||
ident=args.principal |
ident=args.principal |
||||
output_style=args.output |
output_style=args.output |
||||
|
|
||||
# set the limit high so that all data is returned |
# set the limit high so that all data is returned |
||||
limitval=10000 |
limitval=10000 |
||||
|
|
||||
# Define columns we want to output for each rule item (whether the item has a value for that column or not) |
# Define columns we want to output for each rule item (whether the item has a value for that column or not) |
||||
desired_output_columns=['objectUri','containerUri','principalType','principal','setting','permissions','description','reason','createdBy','createdTimestamp','modifiedBy','modifiedTimestamp','condition','matchParams','mediaType','enabled','version'] |
desired_output_columns=['objectUri','containerUri','principalType','principal','setting','permissions','description','reason','createdBy','createdTimestamp','modifiedBy','modifiedTimestamp','condition','matchParams','mediaType','enabled','version'] |
||||
valid_permissions=['read','update','delete','secure','add','remove','create'] |
valid_permissions=['read','update','delete','secure','add','remove','create'] |
||||
|
|
||||
# build the request depending on what options were passed in |
# build the request depending on what options were passed in |
||||
if ident.lower()=='authenticatedusers': ident='authenticatedUsers' |
if ident.lower()=='authenticatedusers': ident='authenticatedUsers' |
||||
|
|
||||
if ident=='none' and objuri=='none': reqval= "/authorization/rules" |
if ident=='none' and objuri=='none': reqval= "/authorization/rules" |
||||
elif ident=='none' and objuri != 'none': reqval= "/authorization/rules?filter=contains(objectUri,'"+objuri+"')" |
elif ident=='none' and objuri != 'none': reqval= "/authorization/rules?filter=contains(objectUri,'"+objuri+"')" |
||||
elif ident!='none' and objuri == 'none': |
elif ident!='none' and objuri == 'none': |
||||
if ident=='guest' or ident=='everyone' or ident=='authenticatedUsers': |
if ident=='guest' or ident=='everyone' or ident=='authenticatedUsers': |
||||
reqval= "/authorization/rules?filter=eq(principalType,'"+ident+"')" |
reqval= "/authorization/rules?filter=eq(principalType,'"+ident+"')" |
||||
else: |
else: |
||||
reqval= "/authorization/rules?filter=eq(principal,'"+ident+"')" |
reqval= "/authorization/rules?filter=eq(principal,'"+ident+"')" |
||||
elif ident!='none' and objuri != 'none': |
elif ident!='none' and objuri != 'none': |
||||
|
|
||||
if ident=='guest' or ident=='everyone' or ident=='authenticatedUsers': |
if ident=='guest' or ident=='everyone' or ident=='authenticatedUsers': |
||||
reqval= "/authorization/rules?filter=and(eq(principalType,'"+ident+"'),contains(objectUri,'"+objuri+"'))" |
reqval= "/authorization/rules?filter=and(eq(principalType,'"+ident+"'),contains(objectUri,'"+objuri+"'))" |
||||
else: |
else: |
||||
reqval= "/authorization/rules?filter=and(eq(principal,'"+ident+"'),contains(objectUri,'"+objuri+"'))" |
reqval= "/authorization/rules?filter=and(eq(principal,'"+ident+"'),contains(objectUri,'"+objuri+"'))" |
||||
|
|
||||
if ident=='none' and objuri=='none': reqval=reqval+'?limit='+str(limitval) |
if ident=='none' and objuri=='none': reqval=reqval+'?limit='+str(limitval) |
||||
else: reqval=reqval+'&limit='+str(limitval) |
else: reqval=reqval+'&limit='+str(limitval) |
||||
|
|
||||
reqtype='get' |
reqtype='get' |
||||
|
|
||||
#make the rest call |
#make the rest call |
||||
rules_result_json=callrestapi(reqval,reqtype) |
rules_result_json=callrestapi(reqval,reqtype) |
||||
|
|
||||
#print(rules_result_json) |
#print(rules_result_json) |
||||
#print('rules_result_json is a '+type(rules_result_json).__name__+' object') #rules_result_json is a dict object |
#print('rules_result_json is a '+type(rules_result_json).__name__+' object') #rules_result_json is a dict object |
||||
|
|
||||
#print the result if output style is json or simple |
#print the result if output style is json or simple |
||||
if output_style in ['json','simple']: |
if output_style in ['json','simple']: |
||||
printresult(rules_result_json,output_style) |
printresult(rules_result_json,output_style) |
||||
elif output_style=='csv': |
elif output_style=='csv': |
||||
# Print a header row |
# Print a header row |
||||
print(','.join(map(str,desired_output_columns))) |
print(','.join(map(str,desired_output_columns))) |
||||
if 'items' in rules_result_json: |
if 'items' in rules_result_json: |
||||
#print "There are " + str(rules_result_json['count']) + " rules" |
#print "There are " + str(rules_result_json['count']) + " rules" |
||||
for item in rules_result_json['items']: |
for item in rules_result_json['items']: |
||||
outstr='' |
outstr='' |
||||
#print(item) |
#print(item) |
||||
for column in desired_output_columns: |
for column in desired_output_columns: |
||||
# Add a comma to the output string, even if we will not output anything else, unless this is the very first desired output column |
# Add a comma to the output string, even if we will not output anything else, unless this is the very first desired output column |
||||
if column is not desired_output_columns[0]: outstr=outstr+',' |
if column is not desired_output_columns[0]: outstr=outstr+',' |
||||
if column=='setting': |
if column=='setting': |
||||
# The setting value is derived from two columns: type and condition. |
# The setting value is derived from two columns: type and condition. |
||||
if 'condition' in item: |
if 'condition' in item: |
||||
#print("Condition found") |
#print("Condition found") |
||||
outstr=outstr+'conditional '+item['type'] |
outstr=outstr+'conditional '+item['type'] |
||||
else: |
else: |
||||
outstr=outstr+item['type'] |
outstr=outstr+item['type'] |
||||
elif column in item: |
elif column in item: |
||||
# This column is in the results item for this rule |
# This column is in the results item for this rule |
||||
# Most columns are straight strings, but a few need special handling |
# Most columns are straight strings, but a few need special handling |
||||
if column in ['condition','description','reason']: |
if column in ['condition','description','reason']: |
||||
# The these strings can have values whcih contain commas, need we to quote them to avoid the commas being interpreted as column separators in the CSV |
# The these strings can have values whcih contain commas, need we to quote them to avoid the commas being interpreted as column separators in the CSV |
||||
outstr=outstr+'"'+item[column]+'"' |
outstr=outstr+'"'+item[column]+'"' |
||||
elif column=='permissions': |
elif column=='permissions': |
||||
# Construct a string listing each permission in the correct order, separated by spaces and surrounded by square brackets |
# Construct a string listing each permission in the correct order, separated by spaces and surrounded by square brackets |
||||
outstr=outstr+'[' |
outstr=outstr+'[' |
||||
permstr='' |
permstr='' |
||||
# Output permissions in the order we choose, not the order they appear in the result item |
# Output permissions in the order we choose, not the order they appear in the result item |
||||
for permission in valid_permissions: |
for permission in valid_permissions: |
||||
for result_permission in item['permissions']: |
for result_permission in item['permissions']: |
||||
if permission == result_permission: |
if permission == result_permission: |
||||
# Add a space to separate permissions if this isn't the first permission |
# Add a space to separate permissions if this isn't the first permission |
||||
if not permstr=='': permstr=permstr+' ' |
if not permstr=='': permstr=permstr+' ' |
||||
permstr=permstr+result_permission |
permstr=permstr+result_permission |
||||
outstr=outstr+permstr+']' |
outstr=outstr+permstr+']' |
||||
else: |
else: |
||||
# Normal column |
# Normal column |
||||
# Some columns contain non-string values: matchParams and enabled are boolean, version is integer. Convert everything to a string. |
# Some columns contain non-string values: matchParams and enabled are boolean, version is integer. Convert everything to a string. |
||||
outstr=outstr+str(item[column]) |
outstr=outstr+str(item[column]) |
||||
print(outstr) |
print(outstr) |
||||
else: |
else: |
||||
print "output_style can be json, simple or csv. You specified " + output_style + " which is invalid." |
print "output_style can be json, simple or csv. You specified " + output_style + " which is invalid." |
||||
|
|
||||
|
|||||
@ -1,59 +1,59 @@ |
|||||
#!/usr/bin/python |
#!/usr/bin/python |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# |
# |
||||
# IMPORTANT: calls the sas-admin cli change the variable below if your CLI is not |
# IMPORTANT: calls the sas-admin cli change the variable below if your CLI is not |
||||
# installed in the default location |
# installed in the default location |
||||
# |
# |
||||
# usage python loginviauthinfo.py |
# usage python loginviauthinfo.py |
||||
# |
# |
||||
# Change History |
# Change History |
||||
# |
# |
||||
# |
# |
||||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
# Licensed under the Apache License, Version 2.0 (the License); |
# Licensed under the Apache License, Version 2.0 (the License); |
||||
# you may not use this file except in compliance with the License. |
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
# You may obtain a copy of the License at |
||||
# |
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
# Unless required by applicable law or agreed to in writing, software |
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
# limitations under the License. |
||||
# |
# |
||||
from __future__ import print_function |
from __future__ import print_function |
||||
import netrc |
import netrc |
||||
import subprocess |
import subprocess |
||||
import platform |
import platform |
||||
import os |
import os |
||||
import argparse |
import argparse |
||||
|
|
||||
# CHANGE THIS VARIABLE IF YOUR CLI IS IN A DIFFERENT LOCATION |
# CHANGE THIS VARIABLE IF YOUR CLI IS IN A DIFFERENT LOCATION |
||||
clidir='/opt/sas/viya/home/bin/' |
clidir='/opt/sas/viya/home/bin/' |
||||
#clidir='c:\\admincli\\' |
#clidir='c:\\admincli\\' |
||||
|
|
||||
# get input parameters |
# get input parameters |
||||
parser = argparse.ArgumentParser(description="Authinfo File") |
parser = argparse.ArgumentParser(description="Authinfo File") |
||||
parser.add_argument("-f","--file", help="Enter the path to the authinfo file.",default='.authinfo') |
parser.add_argument("-f","--file", help="Enter the path to the authinfo file.",default='.authinfo') |
||||
args = parser.parse_args() |
args = parser.parse_args() |
||||
authfile=args.file |
authfile=args.file |
||||
|
|
||||
host=platform.node() |
host=platform.node() |
||||
|
|
||||
# Read from the authinfo file in your home directory |
# Read from the authinfo file in your home directory |
||||
fname=os.path.join(os.path.expanduser('~'),authfile) |
fname=os.path.join(os.path.expanduser('~'),authfile) |
||||
|
|
||||
cur_profile=os.environ.get("SAS_CLI_PROFILE","Default") |
cur_profile=os.environ.get("SAS_CLI_PROFILE","Default") |
||||
print("Logging in with profile: ",cur_profile ) |
print("Logging in with profile: ",cur_profile ) |
||||
|
|
||||
if os.path.isfile(fname): |
if os.path.isfile(fname): |
||||
|
|
||||
secrets = netrc.netrc(fname) |
secrets = netrc.netrc(fname) |
||||
username, account, password = secrets.authenticators( host ) |
username, account, password = secrets.authenticators( host ) |
||||
command=clidir+'sas-admin --profile '+cur_profile+ ' auth login -u '+username+ ' -p '+password |
command=clidir+'sas-admin --profile '+cur_profile+ ' auth login -u '+username+ ' -p '+password |
||||
subprocess.call(command, shell=True) |
subprocess.call(command, shell=True) |
||||
|
|
||||
else: |
else: |
||||
print('ERROR: '+fname+' does not exist') |
print('ERROR: '+fname+' does not exist') |
||||
@ -1,65 +1,65 @@ |
|||||
#!/usr/bin/python |
#!/usr/bin/python |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# |
# |
||||
# showsetup.py |
# showsetup.py |
||||
# |
# |
||||
# output some system settings to help with debugging issues |
# output some system settings to help with debugging issues |
||||
# |
# |
||||
# October 2018 |
# October 2018 |
||||
# |
# |
||||
# |
# |
||||
# Change History |
# Change History |
||||
# |
# |
||||
# |
# |
||||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
# Licensed under the Apache License, Version 2.0 (the License); |
# Licensed under the Apache License, Version 2.0 (the License); |
||||
# you may not use this file except in compliance with the License. |
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
# You may obtain a copy of the License at |
||||
# |
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
# Unless required by applicable law or agreed to in writing, software |
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
# limitations under the License. |
||||
# |
# |
||||
|
|
||||
import sys |
import sys |
||||
import requests |
import requests |
||||
import os |
import os |
||||
|
|
||||
from sharedfunctions import getprofileinfo |
from sharedfunctions import getprofileinfo |
||||
|
|
||||
# software versions |
# software versions |
||||
print("Python Version is: "+str(sys.version_info[0])+'.'+str(sys.version_info[1])) |
print("Python Version is: "+str(sys.version_info[0])+'.'+str(sys.version_info[1])) |
||||
print("Requests Version is: "+requests.__version__) |
print("Requests Version is: "+requests.__version__) |
||||
|
|
||||
# profile |
# profile |
||||
|
|
||||
cur_profile=os.environ.get("SAS_CLI_PROFILE","NOTSET") |
cur_profile=os.environ.get("SAS_CLI_PROFILE","NOTSET") |
||||
|
|
||||
if cur_profile=="NOTSET": |
if cur_profile=="NOTSET": |
||||
print("SAS_CLI_PROFILE environment variable not set, using Default profile") |
print("SAS_CLI_PROFILE environment variable not set, using Default profile") |
||||
cur_profile='Default' |
cur_profile='Default' |
||||
else: |
else: |
||||
print("SAS_CLI_PROFILE environment variable set to profile "+ cur_profile) |
print("SAS_CLI_PROFILE environment variable set to profile "+ cur_profile) |
||||
|
|
||||
|
|
||||
ssl_file=os.environ.get("SSL_CERT_FILE","NOTSET") |
ssl_file=os.environ.get("SSL_CERT_FILE","NOTSET") |
||||
|
|
||||
if ssl_file=="NOTSET": |
if ssl_file=="NOTSET": |
||||
print("SSL_CERT_FILE environment variable not set.") |
print("SSL_CERT_FILE environment variable not set.") |
||||
else: |
else: |
||||
print("SSL_CERT_FILE environment variable set to profile "+ ssl_file) |
print("SSL_CERT_FILE environment variable set to profile "+ ssl_file) |
||||
|
|
||||
|
|
||||
r_ssl_file=os.environ.get("REQUESTS_CA_BUNDLE","NOTSET") |
r_ssl_file=os.environ.get("REQUESTS_CA_BUNDLE","NOTSET") |
||||
|
|
||||
if r_ssl_file=="NOTSET": |
if r_ssl_file=="NOTSET": |
||||
print("REQUESTS_CA_BUNDLE environment variable not set.") |
print("REQUESTS_CA_BUNDLE environment variable not set.") |
||||
else: |
else: |
||||
print("REQUESTS_CA_BUNDLE environment variable set to profile "+ r_ssl_file) |
print("REQUESTS_CA_BUNDLE environment variable set to profile "+ r_ssl_file) |
||||
|
|
||||
getprofileinfo(cur_profile) |
getprofileinfo(cur_profile) |
||||
|
|||||
@ -1,139 +1,139 @@ |
|||||
#!/usr/bin/sh |
#!/usr/bin/sh |
||||
# |
# |
||||
# unittestsadm33.sh |
# unittestsadm33.sh |
||||
# June 2018 |
# June 2018 |
||||
# |
# |
||||
# Calls each of the pyviyatools at least once, as a simple unit/integration test |
# Calls each of the pyviyatools at least once, as a simple unit/integration test |
||||
# |
# |
||||
# Some tests are provided with example folder paths which are not likely to |
# Some tests are provided with example folder paths which are not likely to |
||||
# exist in your deployment. However, most tests are not dependent on any |
# exist in your deployment. However, most tests are not dependent on any |
||||
# custom content in the deployment, and will run well on any deployment. |
# custom content in the deployment, and will run well on any deployment. |
||||
# |
# |
||||
# Some tests intentionally do things which do not work, e.g. delete a folder |
# Some tests intentionally do things which do not work, e.g. delete a folder |
||||
# which does not exist. The error message returned by the tool called is |
# which does not exist. The error message returned by the tool called is |
||||
# considered sufficient to demonstrate that it has in fact been called, and is |
# considered sufficient to demonstrate that it has in fact been called, and is |
||||
# working as intended. If you like, you could create content for these tests |
# working as intended. If you like, you could create content for these tests |
||||
# to act on, e.g. create a folder called "/this_folder_does_not_exist", and |
# to act on, e.g. create a folder called "/this_folder_does_not_exist", and |
||||
# allow one of the tests below delete it. |
# allow one of the tests below delete it. |
||||
# |
# |
||||
# The following tests create new content, and do not clean up after themselves: |
# The following tests create new content, and do not clean up after themselves: |
||||
# 1. "Create a domain using createdomain" |
# 1. "Create a domain using createdomain" |
||||
# - creates or replaces domain named 'test', does not create multiple |
# - creates or replaces domain named 'test', does not create multiple |
||||
# copies |
# copies |
||||
# 2. "Create a binary backup job" |
# 2. "Create a binary backup job" |
||||
# - creates a new scheduled job named 'BINARY_BACKUP_JOB' each time it |
# - creates a new scheduled job named 'BINARY_BACKUP_JOB' each time it |
||||
# runs, will create multiple copies |
# runs, will create multiple copies |
||||
# You may wish to clean up after them manually, especially in a |
# You may wish to clean up after them manually, especially in a |
||||
# real customer environment. Study the tests and/or run them individually |
# real customer environment. Study the tests and/or run them individually |
||||
# to learn more about what they create, so that you can find and delete it |
# to learn more about what they create, so that you can find and delete it |
||||
# yourself. In a dev, PoC, playpen or classroom environment, the cleanup |
# yourself. In a dev, PoC, playpen or classroom environment, the cleanup |
||||
# might be optional, as the created objects will not interfere with other |
# might be optional, as the created objects will not interfere with other |
||||
# content or work. |
# content or work. |
||||
# |
# |
||||
# Change History |
# Change History |
||||
# |
# |
||||
# 01Jun2018 Initial version after refactoring tools |
# 01Jun2018 Initial version after refactoring tools |
||||
# 18oct2018 updated gerrulid test because -o changed to -u |
# 18oct2018 updated gerrulid test because -o changed to -u |
||||
# |
# |
||||
# |
# |
||||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
# You may obtain a copy of the License at |
||||
# |
# |
||||
# https://www.apache.org/licenses/LICENSE-2.0 |
# https://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
# Unless required by applicable law or agreed to in writing, software |
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
# limitations under the License. |
||||
|
|
||||
|
|
||||
echo "Return all the rest calls that can be made to the folders endpoint" |
echo "Return all the rest calls that can be made to the folders endpoint" |
||||
./callrestapi.py -e /folders -m get |
./callrestapi.py -e /folders -m get |
||||
echo |
echo |
||||
|
|
||||
echo "Return the json for all the folders/folders" |
echo "Return the json for all the folders/folders" |
||||
./callrestapi.py -e /folders/folders -m get |
./callrestapi.py -e /folders/folders -m get |
||||
echo |
echo |
||||
|
|
||||
echo "Return simple text for all the folders/folders" |
echo "Return simple text for all the folders/folders" |
||||
./callrestapi.py -e /folders/folders -m get -o simple |
./callrestapi.py -e /folders/folders -m get -o simple |
||||
echo |
echo |
||||
|
|
||||
echo "Rest calls often limit the results returned the text output will tell you returned and total available items" |
echo "Rest calls often limit the results returned the text output will tell you returned and total available items" |
||||
echo "in this call set a limit above the total items to see everything" |
echo "in this call set a limit above the total items to see everything" |
||||
./callrestapi.py -e /folders/folders?limit=500 -m get -o simple |
./callrestapi.py -e /folders/folders?limit=500 -m get -o simple |
||||
echo |
echo |
||||
|
|
||||
echo "Return the json for all the identities" |
echo "Return the json for all the identities" |
||||
./callrestapi.py -e /identities/identities -m get |
./callrestapi.py -e /identities/identities -m get |
||||
echo |
echo |
||||
|
|
||||
echo "Return the json for all the identities output to a file" |
echo "Return the json for all the identities output to a file" |
||||
./callrestapi.py -e /identities/identities -m get > /tmp/identities.json |
./callrestapi.py -e /identities/identities -m get > /tmp/identities.json |
||||
echo |
echo |
||||
echo "Contents of /tmp/identities.json:" |
echo "Contents of /tmp/identities.json:" |
||||
cat /tmp/identities.json |
cat /tmp/identities.json |
||||
echo "End of contents of /tmp/identities.json" |
echo "End of contents of /tmp/identities.json" |
||||
echo |
echo |
||||
echo "Deleting /tmp/identities.json" |
echo "Deleting /tmp/identities.json" |
||||
rm /tmp/identities.json |
rm /tmp/identities.json |
||||
echo "Demonstrating that /tmp/identities.json has been deleted - list it, ls should say no such file or directory:" |
echo "Demonstrating that /tmp/identities.json has been deleted - list it, ls should say no such file or directory:" |
||||
ls -al /tmp/identities.json |
ls -al /tmp/identities.json |
||||
echo |
echo |
||||
|
|
||||
echo "Refresh the identities cache" |
echo "Refresh the identities cache" |
||||
./callrestapi.py -e /identities/userCount -m get |
./callrestapi.py -e /identities/userCount -m get |
||||
./callrestapi.py -e /identities/cache/refreshes -m post |
./callrestapi.py -e /identities/cache/refreshes -m post |
||||
echo |
echo |
||||
|
|
||||
echo "Pass the folder path and return the folder id and uri" |
echo "Pass the folder path and return the folder id and uri" |
||||
./getfolderid.py -f /gelcontent |
./getfolderid.py -f /gelcontent |
||||
echo |
echo |
||||
|
|
||||
echo "Delete a folder based on its path - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
echo "Delete a folder based on its path - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
||||
./deletefolder.py -f /this_folder_does_not_exist |
./deletefolder.py -f /this_folder_does_not_exist |
||||
echo |
echo |
||||
|
|
||||
echo "Delete a folder and its content - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
echo "Delete a folder and its content - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
||||
./deletefolderandcontent.py -f /this_folder_does_not_exist |
./deletefolderandcontent.py -f /this_folder_does_not_exist |
||||
echo |
echo |
||||
|
|
||||
echo "Return a set of configuration properties" |
echo "Return a set of configuration properties" |
||||
./getconfigurationproperties.py -c sas.identities.providers.ldap.user |
./getconfigurationproperties.py -c sas.identities.providers.ldap.user |
||||
echo |
echo |
||||
|
|
||||
echo "Create a domain using createdomain" |
echo "Create a domain using createdomain" |
||||
./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HRs,Sales" |
./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HRs,Sales" |
||||
echo |
echo |
||||
|
|
||||
echo "Create a binary backup job" |
echo "Create a binary backup job" |
||||
./createbinarybackup.py |
./createbinarybackup.py |
||||
echo |
echo |
||||
|
|
||||
echo "Get a rule ID" |
echo "Get a rule ID" |
||||
#Get /Public folder ID |
#Get /Public folder ID |
||||
./getfolderid.py --folderpath /Public > /tmp/folderid.txt |
./getfolderid.py --folderpath /Public > /tmp/folderid.txt |
||||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
||||
echo "The Public folder ID is" $id |
echo "The Public folder ID is" $id |
||||
./getruleid.py -u /folders/folders/$id/** -p authenticatedUsers |
./getruleid.py -u /folders/folders/$id/** -p authenticatedUsers |
||||
echo |
echo |
||||
|
|
||||
echo "Move all content from one folder to another folder (or in this case, the same folder)" |
echo "Move all content from one folder to another folder (or in this case, the same folder)" |
||||
./movecontent.py -s /gelcontent/GELCorp/Shared/Reports -t /gelcontent/GELCorp/Shared/Reports -q |
./movecontent.py -s /gelcontent/GELCorp/Shared/Reports -t /gelcontent/GELCorp/Shared/Reports -q |
||||
echo |
echo |
||||
|
|
||||
echo "Test folder access" |
echo "Test folder access" |
||||
./testfolderaccess.py -f '/gelcontent/GELCorp' -n gelcorp -t group -m read -s grant |
./testfolderaccess.py -f '/gelcontent/GELCorp' -n gelcorp -t group -m read -s grant |
||||
echo |
echo |
||||
|
|
||||
echo "Display all sasadministrator rules" |
echo "Display all sasadministrator rules" |
||||
./listrules.py --p SASadministrators -o simple |
./listrules.py --p SASadministrators -o simple |
||||
echo |
echo |
||||
|
|
||||
echo "Display all rules that contain SASVisual in the URI" |
echo "Display all rules that contain SASVisual in the URI" |
||||
./listrules.py -u SASVisual -o simple |
./listrules.py -u SASVisual -o simple |
||||
echo |
echo |
||||
|
|||||
@ -1,181 +1,181 @@ |
|||||
#!/usr/bin/sh |
#!/usr/bin/sh |
||||
# |
# |
||||
# unittestsadm33.sh |
# unittestsadm33.sh |
||||
# December 2018 |
# December 2018 |
||||
# |
# |
||||
# Calls each of the pyviyatools at least once, as a simple unit/integration test |
# Calls each of the pyviyatools at least once, as a simple unit/integration test |
||||
# |
# |
||||
# Some tests are provided with example folder paths which are not likely to |
# Some tests are provided with example folder paths which are not likely to |
||||
# exist in your deployment. However, most tests are not dependent on any |
# exist in your deployment. However, most tests are not dependent on any |
||||
# custom content in the deployment, and will run well on any deployment. |
# custom content in the deployment, and will run well on any deployment. |
||||
# |
# |
||||
# Some tests intentionally do things which do not work, e.g. delete a folder |
# Some tests intentionally do things which do not work, e.g. delete a folder |
||||
# which does not exist. The error message returned by the tool called is |
# which does not exist. The error message returned by the tool called is |
||||
# considered sufficient to demonstrate that it has in fact been called, and is |
# considered sufficient to demonstrate that it has in fact been called, and is |
||||
# working as intended. If you like, you could create content for these tests |
# working as intended. If you like, you could create content for these tests |
||||
# to act on, e.g. create a folder called "/this_folder_does_not_exist", and |
# to act on, e.g. create a folder called "/this_folder_does_not_exist", and |
||||
# allow one of the tests below delete it. |
# allow one of the tests below delete it. |
||||
# |
# |
||||
# The following tests create new content, and do not clean up after themselves: |
# The following tests create new content, and do not clean up after themselves: |
||||
# 1. "Create a domain using createdomain" |
# 1. "Create a domain using createdomain" |
||||
# - creates or replaces domain named 'test', does not create multiple |
# - creates or replaces domain named 'test', does not create multiple |
||||
# copies |
# copies |
||||
# 2. "Create a binary backup job" |
# 2. "Create a binary backup job" |
||||
# - creates a new scheduled job named 'BINARY_BACKUP_JOB' each time it |
# - creates a new scheduled job named 'BINARY_BACKUP_JOB' each time it |
||||
# runs, will create multiple copies |
# runs, will create multiple copies |
||||
# You may wish to clean up after them manually, especially in a |
# You may wish to clean up after them manually, especially in a |
||||
# real customer environment. Study the tests and/or run them individually |
# real customer environment. Study the tests and/or run them individually |
||||
# to learn more about what they create, so that you can find and delete it |
# to learn more about what they create, so that you can find and delete it |
||||
# yourself. In a dev, PoC, playpen or classroom environment, the cleanup |
# yourself. In a dev, PoC, playpen or classroom environment, the cleanup |
||||
# might be optional, as the created objects will not interfere with other |
# might be optional, as the created objects will not interfere with other |
||||
# content or work. |
# content or work. |
||||
# |
# |
||||
# Change History |
# Change History |
||||
# |
# |
||||
# 01Jun2018 Initial version after refactoring tools |
# 01Jun2018 Initial version after refactoring tools |
||||
# 18Oct2018 updated gerrulid test because -o changed to -u |
# 18Oct2018 updated gerrulid test because -o changed to -u |
||||
# 03Dec2018 Added tests for explainaccess.py |
# 03Dec2018 Added tests for explainaccess.py |
||||
# |
# |
||||
# |
# |
||||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
# You may obtain a copy of the License at |
||||
# |
# |
||||
# https://www.apache.org/licenses/LICENSE-2.0 |
# https://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
# Unless required by applicable law or agreed to in writing, software |
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
# limitations under the License. |
||||
|
|
||||
|
|
||||
echo "Return all the rest calls that can be made to the folders endpoint" |
echo "Return all the rest calls that can be made to the folders endpoint" |
||||
./callrestapi.py -e /folders -m get |
./callrestapi.py -e /folders -m get |
||||
echo |
echo |
||||
|
|
||||
echo "Return the json for all the folders/folders" |
echo "Return the json for all the folders/folders" |
||||
./callrestapi.py -e /folders/folders -m get |
./callrestapi.py -e /folders/folders -m get |
||||
echo |
echo |
||||
|
|
||||
echo "Return simple text for all the folders/folders" |
echo "Return simple text for all the folders/folders" |
||||
./callrestapi.py -e /folders/folders -m get -o simple |
./callrestapi.py -e /folders/folders -m get -o simple |
||||
echo |
echo |
||||
|
|
||||
echo "Rest calls often limit the results returned the text output will tell you returned and total available items" |
echo "Rest calls often limit the results returned the text output will tell you returned and total available items" |
||||
echo "in this call set a limit above the total items to see everything" |
echo "in this call set a limit above the total items to see everything" |
||||
./callrestapi.py -e /folders/folders?limit=500 -m get -o simple |
./callrestapi.py -e /folders/folders?limit=500 -m get -o simple |
||||
echo |
echo |
||||
|
|
||||
echo "Return the json for all the identities" |
echo "Return the json for all the identities" |
||||
./callrestapi.py -e /identities/identities -m get |
./callrestapi.py -e /identities/identities -m get |
||||
echo |
echo |
||||
|
|
||||
echo "Return the json for all the identities output to a file" |
echo "Return the json for all the identities output to a file" |
||||
./callrestapi.py -e /identities/identities -m get > /tmp/identities.json |
./callrestapi.py -e /identities/identities -m get > /tmp/identities.json |
||||
echo |
echo |
||||
echo "Contents of /tmp/identities.json:" |
echo "Contents of /tmp/identities.json:" |
||||
cat /tmp/identities.json |
cat /tmp/identities.json |
||||
echo "End of contents of /tmp/identities.json" |
echo "End of contents of /tmp/identities.json" |
||||
echo |
echo |
||||
echo "Deleting /tmp/identities.json" |
echo "Deleting /tmp/identities.json" |
||||
rm /tmp/identities.json |
rm /tmp/identities.json |
||||
echo "Demonstrating that /tmp/identities.json has been deleted - list it, ls should say no such file or directory:" |
echo "Demonstrating that /tmp/identities.json has been deleted - list it, ls should say no such file or directory:" |
||||
ls -al /tmp/identities.json |
ls -al /tmp/identities.json |
||||
echo |
echo |
||||
|
|
||||
echo "Refresh the identities cache" |
echo "Refresh the identities cache" |
||||
./callrestapi.py -e /identities/userCount -m get |
./callrestapi.py -e /identities/userCount -m get |
||||
./callrestapi.py -e /identities/cache/refreshes -m post |
./callrestapi.py -e /identities/cache/refreshes -m post |
||||
echo |
echo |
||||
|
|
||||
echo "Pass the folder path and return the folder id and uri" |
echo "Pass the folder path and return the folder id and uri" |
||||
./getfolderid.py -f /gelcontent |
./getfolderid.py -f /gelcontent |
||||
echo |
echo |
||||
|
|
||||
echo "Delete a folder based on its path - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
echo "Delete a folder based on its path - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
||||
./deletefolder.py -f /this_folder_does_not_exist |
./deletefolder.py -f /this_folder_does_not_exist |
||||
echo |
echo |
||||
|
|
||||
echo "Delete a folder and its content - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
echo "Delete a folder and its content - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
||||
./deletefolderandcontent.py -f /this_folder_does_not_exist |
./deletefolderandcontent.py -f /this_folder_does_not_exist |
||||
echo |
echo |
||||
|
|
||||
echo "Return a set of configuration properties" |
echo "Return a set of configuration properties" |
||||
./getconfigurationproperties.py -c sas.identities.providers.ldap.user |
./getconfigurationproperties.py -c sas.identities.providers.ldap.user |
||||
echo |
echo |
||||
|
|
||||
echo "Create a domain using createdomain" |
echo "Create a domain using createdomain" |
||||
./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HR,Sales" |
./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HR,Sales" |
||||
echo |
echo |
||||
|
|
||||
# Commented out for Viya 3.4 version: this tool is only intended for use with Viya 3.3 |
# Commented out for Viya 3.4 version: this tool is only intended for use with Viya 3.3 |
||||
#echo "Create a binary backup job" |
#echo "Create a binary backup job" |
||||
#./createbinarybackup.py |
#./createbinarybackup.py |
||||
#echo |
#echo |
||||
|
|
||||
echo "Get a rule ID" |
echo "Get a rule ID" |
||||
#Get /Public folder ID |
#Get /Public folder ID |
||||
./getfolderid.py --folderpath /Public > /tmp/folderid.txt |
./getfolderid.py --folderpath /Public > /tmp/folderid.txt |
||||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
||||
echo "The Public folder ID is" $id |
echo "The Public folder ID is" $id |
||||
./getruleid.py -u /folders/folders/$id/** -p authenticatedUsers |
./getruleid.py -u /folders/folders/$id/** -p authenticatedUsers |
||||
echo |
echo |
||||
|
|
||||
echo "Move all content from one folder to another folder (or in this case, the same folder)" |
echo "Move all content from one folder to another folder (or in this case, the same folder)" |
||||
./movecontent.py -s /gelcontent/GELCorp/Shared/Reports -t /gelcontent/GELCorp/Shared/Reports -q |
./movecontent.py -s /gelcontent/GELCorp/Shared/Reports -t /gelcontent/GELCorp/Shared/Reports -q |
||||
echo |
echo |
||||
|
|
||||
echo "Test folder access" |
echo "Test folder access" |
||||
./testfolderaccess.py -f '/gelcontent/GELCorp' -n gelcorp -t group -m read -s grant |
./testfolderaccess.py -f '/gelcontent/GELCorp' -n gelcorp -t group -m read -s grant |
||||
echo |
echo |
||||
|
|
||||
echo "Display all sasadministrator rules" |
echo "Display all sasadministrator rules" |
||||
./listrules.py --p SASadministrators -o simple |
./listrules.py --p SASadministrators -o simple |
||||
echo |
echo |
||||
|
|
||||
echo "Display all rules that contain SASVisual in the URI" |
echo "Display all rules that contain SASVisual in the URI" |
||||
./listrules.py -u SASVisual -o simple |
./listrules.py -u SASVisual -o simple |
||||
echo |
echo |
||||
|
|
||||
echo "Create folders from a CSV file" |
echo "Create folders from a CSV file" |
||||
./createfolders.py -h |
./createfolders.py -h |
||||
echo |
echo |
||||
|
|
||||
echo Update the theme for the user sasadm |
echo Update the theme for the user sasadm |
||||
./updatepreferences.py -t user -tn sasadm -pi OpenUI.Theme.Default -pv sas_hcb |
./updatepreferences.py -t user -tn sasadm -pi OpenUI.Theme.Default -pv sas_hcb |
||||
echo |
echo |
||||
|
|
||||
echo "Explain permissions for the folder /gelcontent/GELCorp, with no header row." |
echo "Explain permissions for the folder /gelcontent/GELCorp, with no header row." |
||||
./explainaccess.py -f /gelcontent/GELCorp |
./explainaccess.py -f /gelcontent/GELCorp |
||||
echo |
echo |
||||
|
|
||||
echo "Explain permissions for the folder /gelcontent/GELCorp, with no header row, for Heather." |
echo "Explain permissions for the folder /gelcontent/GELCorp, with no header row, for Heather." |
||||
./explainaccess.py -f /gelcontent/GELCorp -n Heather -t user |
./explainaccess.py -f /gelcontent/GELCorp -n Heather -t user |
||||
echo |
echo |
||||
|
|
||||
echo "Explain permissions for the folder /gelcontent/GELCorp, with a header row, and include the folder path." |
echo "Explain permissions for the folder /gelcontent/GELCorp, with a header row, and include the folder path." |
||||
./explainaccess.py -f /gelcontent/GELCorp --header -p |
./explainaccess.py -f /gelcontent/GELCorp --header -p |
||||
echo |
echo |
||||
|
|
||||
echo "Explain permissions for the folder /gelcontent/GELCorp, showing only rows with at least one direct permission." |
echo "Explain permissions for the folder /gelcontent/GELCorp, showing only rows with at least one direct permission." |
||||
./explainaccess.py -f /gelcontent/GELCorp --direct_only |
./explainaccess.py -f /gelcontent/GELCorp --direct_only |
||||
echo |
echo |
||||
|
|
||||
echo "Explain permissions for several application capabilities. Notice that there are no conveyed permissions in the results" |
echo "Explain permissions for several application capabilities. Notice that there are no conveyed permissions in the results" |
||||
./explainaccess.py -u /SASEnvironmentManager/dashboard --header -p -l read update delete secure add remove create |
./explainaccess.py -u /SASEnvironmentManager/dashboard --header -p -l read update delete secure add remove create |
||||
./explainaccess.py -u /SASDataStudio/** -p -l read update delete secure add remove create |
./explainaccess.py -u /SASDataStudio/** -p -l read update delete secure add remove create |
||||
./explainaccess.py -u /SASDataExplorer/** -p -l read update delete secure add remove create |
./explainaccess.py -u /SASDataExplorer/** -p -l read update delete secure add remove create |
||||
./explainaccess.py -u /SASVisualAnalytics_capabilities/buildAnalyticalModel -p -l read update delete secure add remove create |
./explainaccess.py -u /SASVisualAnalytics_capabilities/buildAnalyticalModel -p -l read update delete secure add remove create |
||||
echo |
echo |
||||
|
|
||||
echo "Explain the permissions for a folder expressed as a URI. This works with any kind of object, not just folders" |
echo "Explain the permissions for a folder expressed as a URI. This works with any kind of object, not just folders" |
||||
echo "Uses the default permissions list. Specify -c true to include conveyed permissions, as they are not included by default when you use the -u URI parameter." |
echo "Uses the default permissions list. Specify -c true to include conveyed permissions, as they are not included by default when you use the -u URI parameter." |
||||
#Get /gelcontent/GELCorp folder ID |
#Get /gelcontent/GELCorp folder ID |
||||
./getfolderid.py --folderpath /gelcontent/GELCorp > /tmp/folderid.txt |
./getfolderid.py --folderpath /gelcontent/GELCorp > /tmp/folderid.txt |
||||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
||||
./explainaccess.py -u /folders/folders/$id --header -p -c true |
./explainaccess.py -u /folders/folders/$id --header -p -c true |
||||
echo |
echo |
||||
|
|
||||
|
|||||
@ -1,108 +1,108 @@ |
|||||
#!/usr/bin/python |
#!/usr/bin/python |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# |
# |
||||
# updatedomain.py |
# updatedomain.py |
||||
# November 2018 |
# November 2018 |
||||
# |
# |
||||
# update a viya domain to add credentials from a csv |
# update a viya domain to add credentials from a csv |
||||
# the domain must exist |
# the domain must exist |
||||
# |
# |
||||
# Change History |
# Change History |
||||
# |
# |
||||
# 27JAN2017 Comments added |
# 27JAN2017 Comments added |
||||
# 03DEC2018 Strip spaces from the end of users and groups |
# 03DEC2018 Strip spaces from the end of users and groups |
||||
# |
# |
||||
# csv file format |
# csv file format |
||||
# no header row |
# no header row |
||||
# column1 is userid |
# column1 is userid |
||||
# column2 is password |
# column2 is password |
||||
# column3 is identity |
# column3 is identity |
||||
# column4 is identity type (user or group) |
# column4 is identity type (user or group) |
||||
# For example: |
# For example: |
||||
# myuserid,mypass,Sales,group |
# myuserid,mypass,Sales,group |
||||
# acct1,pw1,Admin,user |
# acct1,pw1,Admin,user |
||||
# etc |
# etc |
||||
# |
# |
||||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
#Licensed under the Apache License, Version 2.0 (the "License"); |
#Licensed under the Apache License, Version 2.0 (the "License"); |
||||
#you may not use this file except in compliance with the License. |
#you may not use this file except in compliance with the License. |
||||
#You may obtain a copy of the License at |
#You may obtain a copy of the License at |
||||
# |
# |
||||
# https://www.apache.org/licenses/LICENSE-2.0 |
# https://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
#Unless required by applicable law or agreed to in writing, software |
#Unless required by applicable law or agreed to in writing, software |
||||
#distributed under the License is distributed on an "AS IS" BASIS, |
#distributed under the License is distributed on an "AS IS" BASIS, |
||||
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
#See the License for the specific language governing permissions and |
#See the License for the specific language governing permissions and |
||||
#limitations under the License. |
#limitations under the License. |
||||
|
|
||||
|
|
||||
# Update a domain |
# Update a domain |
||||
|
|
||||
import csv |
import csv |
||||
import base64 |
import base64 |
||||
import argparse |
import argparse |
||||
|
|
||||
from sharedfunctions import callrestapi, file_accessible |
from sharedfunctions import callrestapi, file_accessible |
||||
|
|
||||
parser = argparse.ArgumentParser(description="Update a Viya Domain to add credentials from a csv file.") |
parser = argparse.ArgumentParser(description="Update a Viya Domain to add credentials from a csv file.") |
||||
parser.add_argument("-d","--domain", help="Existing Domain.",required=True) |
parser.add_argument("-d","--domain", help="Existing Domain.",required=True) |
||||
parser.add_argument("-f","--file", help="A csv file containing groups and userids.",required=True) |
parser.add_argument("-f","--file", help="A csv file containing groups and userids.",required=True) |
||||
|
|
||||
args = parser.parse_args() |
args = parser.parse_args() |
||||
|
|
||||
domain_name=args.domain |
domain_name=args.domain |
||||
file=args.file |
file=args.file |
||||
|
|
||||
# check that domain exists |
# check that domain exists |
||||
reqval="/credentials/domains/"+domain_name |
reqval="/credentials/domains/"+domain_name |
||||
reqtype="get" |
reqtype="get" |
||||
|
|
||||
#if domain does not exist call restapi will exit and no additional code is run |
#if domain does not exist call restapi will exit and no additional code is run |
||||
domainexist=callrestapi(reqval,reqtype) |
domainexist=callrestapi(reqval,reqtype) |
||||
|
|
||||
type=domainexist['type'] |
type=domainexist['type'] |
||||
|
|
||||
# read the csv file to create json |
# read the csv file to create json |
||||
check=file_accessible(file,'r') |
check=file_accessible(file,'r') |
||||
|
|
||||
# file can be read |
# file can be read |
||||
if check: |
if check: |
||||
|
|
||||
with open(file, 'rt') as f: |
with open(file, 'rt') as f: |
||||
filecontents = csv.reader(f) |
filecontents = csv.reader(f) |
||||
for row in filecontents: |
for row in filecontents: |
||||
|
|
||||
#print(row) |
#print(row) |
||||
|
|
||||
userid=row[0] |
userid=row[0] |
||||
pwval=row[1] |
pwval=row[1] |
||||
ident=row[2].rstrip() |
ident=row[2].rstrip() |
||||
identtype=row[3].rstrip() |
identtype=row[3].rstrip() |
||||
|
|
||||
|
|
||||
if pwval: cred=base64.b64encode(pwval.encode("utf-8")).decode("utf-8") |
if pwval: cred=base64.b64encode(pwval.encode("utf-8")).decode("utf-8") |
||||
|
|
||||
if identtype=="group": end_ident="groups" |
if identtype=="group": end_ident="groups" |
||||
if identtype=="user": end_ident="users" |
if identtype=="user": end_ident="users" |
||||
|
|
||||
reqval="/credentials/domains/"+domain_name+"/"+end_ident+"/"+ident |
reqval="/credentials/domains/"+domain_name+"/"+end_ident+"/"+ident |
||||
reqtype="put" |
reqtype="put" |
||||
|
|
||||
data = {} |
data = {} |
||||
data['domainId'] = domain_name |
data['domainId'] = domain_name |
||||
data['domainType'] = type |
data['domainType'] = type |
||||
data['identityId'] = ident |
data['identityId'] = ident |
||||
data['identityType'] = identtype |
data['identityType'] = identtype |
||||
data['properties']={"userId": userid} |
data['properties']={"userId": userid} |
||||
if pwval: |
if pwval: |
||||
data['secrets']={"password": cred} |
data['secrets']={"password": cred} |
||||
|
|
||||
#print(reqval) |
#print(reqval) |
||||
#print(data) |
#print(data) |
||||
|
|
||||
# make the rest call |
# make the rest call |
||||
callrestapi(reqval,reqtype,data=data) |
callrestapi(reqval,reqtype,data=data) |
||||
else: |
else: |
||||
print("ERROR: cannot read "+file) |
print("ERROR: cannot read "+file) |
||||
|
|||||
@ -1,99 +1,99 @@ |
|||||
#!/usr/bin/python |
#!/usr/bin/python |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# |
# |
||||
# updatepreferences.py |
# updatepreferences.py |
||||
# October 2018 |
# October 2018 |
||||
# |
# |
||||
# Update user preferences for a single user of a group of users |
# Update user preferences for a single user of a group of users |
||||
# |
# |
||||
# Change History |
# Change History |
||||
# |
# |
||||
# 30OCT2018 first version |
# 30OCT2018 first version |
||||
# |
# |
||||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
||||
# |
# |
||||
#Licensed under the Apache License, Version 2.0 (the "License"); |
#Licensed under the Apache License, Version 2.0 (the "License"); |
||||
#you may not use this file except in compliance with the License. |
#you may not use this file except in compliance with the License. |
||||
#You may obtain a copy of the License at |
#You may obtain a copy of the License at |
||||
# |
# |
||||
# https://www.apache.org/licenses/LICENSE-2.0 |
# https://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
# |
||||
#Unless required by applicable law or agreed to in writing, software |
#Unless required by applicable law or agreed to in writing, software |
||||
#distributed under the License is distributed on an "AS IS" BASIS, |
#distributed under the License is distributed on an "AS IS" BASIS, |
||||
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
#See the License for the specific language governing permissions and |
#See the License for the specific language governing permissions and |
||||
#limitations under the License. |
#limitations under the License. |
||||
|
|
||||
|
|
||||
#################################################################### |
#################################################################### |
||||
#### COMMAND LINE EXAMPLE #### |
#### COMMAND LINE EXAMPLE #### |
||||
#################################################################### |
#################################################################### |
||||
#### ./updatepreferences.py - #### |
#### ./updatepreferences.py - #### |
||||
#### -t user #### |
#### -t user #### |
||||
#### -tn myUser #### |
#### -tn myUser #### |
||||
#### -pi VA.geo.drivedistance.unit #### |
#### -pi VA.geo.drivedistance.unit #### |
||||
#### -pv kilometers #### |
#### -pv kilometers #### |
||||
#################################################################### |
#################################################################### |
||||
#### POSSIBLE VALUES #### |
#### POSSIBLE VALUES #### |
||||
#################################################################### |
#################################################################### |
||||
#### sas.welcome.suppress = true/false #### |
#### sas.welcome.suppress = true/false #### |
||||
#### sas.drive.show.pinned = true/false #### |
#### sas.drive.show.pinned = true/false #### |
||||
#### VA.geo.drivedistance.unit = kilometers/miles #### |
#### VA.geo.drivedistance.unit = kilometers/miles #### |
||||
#### OpenUI.Theme.Default = sas_corporate/sas_inspire/sas_hcb #### |
#### OpenUI.Theme.Default = sas_corporate/sas_inspire/sas_hcb #### |
||||
#################################################################### |
#################################################################### |
||||
|
|
||||
import argparse |
import argparse |
||||
from sharedfunctions import callrestapi |
from sharedfunctions import callrestapi |
||||
|
|
||||
parser = argparse.ArgumentParser(description="Update user preferences for a user or a group of users") |
parser = argparse.ArgumentParser(description="Update user preferences for a user or a group of users") |
||||
parser.add_argument("-t", "--target", help="Type the target of the update: user or group", required=True, choices=['user', 'group']) |
parser.add_argument("-t", "--target", help="Type the target of the update: user or group", required=True, choices=['user', 'group']) |
||||
parser.add_argument("-tn", "--targetname", help="ID of the user or group to which the update applies.", required=True) |
parser.add_argument("-tn", "--targetname", help="ID of the user or group to which the update applies.", required=True) |
||||
parser.add_argument("-pi", "--preferenceid", help="ID of the preference to be updated", required=True) |
parser.add_argument("-pi", "--preferenceid", help="ID of the preference to be updated", required=True) |
||||
parser.add_argument("-pv", "--preferencevalue", help="Value to be set for the preference", required=True) |
parser.add_argument("-pv", "--preferencevalue", help="Value to be set for the preference", required=True) |
||||
|
|
||||
args = parser.parse_args() |
args = parser.parse_args() |
||||
target = args.target |
target = args.target |
||||
targetName = args.targetname |
targetName = args.targetname |
||||
preferenceID = args.preferenceid |
preferenceID = args.preferenceid |
||||
preferenceValue = args.preferencevalue |
preferenceValue = args.preferencevalue |
||||
|
|
||||
json= {"application": "SAS Visual Analytics", "version": 1,"id": preferenceID ,"value": preferenceValue} |
json= {"application": "SAS Visual Analytics", "version": 1,"id": preferenceID ,"value": preferenceValue} |
||||
|
|
||||
# Function to update preference of a specific user |
# Function to update preference of a specific user |
||||
if target == 'user' : |
if target == 'user' : |
||||
|
|
||||
userID=targetName |
userID=targetName |
||||
|
|
||||
reqtype='get' |
reqtype='get' |
||||
reqval="/identities/users/"+userID |
reqval="/identities/users/"+userID |
||||
|
|
||||
userexist=callrestapi(reqval,reqtype) |
userexist=callrestapi(reqval,reqtype) |
||||
|
|
||||
reqtype="put" |
reqtype="put" |
||||
reqval="/preferences/preferences/"+ userID +"/" + preferenceID |
reqval="/preferences/preferences/"+ userID +"/" + preferenceID |
||||
result=callrestapi(reqval,reqtype,data=json) |
result=callrestapi(reqval,reqtype,data=json) |
||||
print("Updating Preference "+reqval+" = "+preferenceValue) |
print("Updating Preference "+reqval+" = "+preferenceValue) |
||||
|
|
||||
|
|
||||
else: # Execute actual code to update the preference for a user or a group |
else: # Execute actual code to update the preference for a user or a group |
||||
|
|
||||
reqtype='get' |
reqtype='get' |
||||
reqval='/identities/groups/'+ targetName +'/members?limit=1000' |
reqval='/identities/groups/'+ targetName +'/members?limit=1000' |
||||
resultdata=callrestapi(reqval,reqtype) |
resultdata=callrestapi(reqval,reqtype) |
||||
|
|
||||
reqtype="put" |
reqtype="put" |
||||
|
|
||||
if 'items' in resultdata: |
if 'items' in resultdata: |
||||
|
|
||||
returned_items=len(resultdata['items']) |
returned_items=len(resultdata['items']) |
||||
for i in range(0,returned_items): |
for i in range(0,returned_items): |
||||
|
|
||||
id=resultdata['items'][i]['id'] |
id=resultdata['items'][i]['id'] |
||||
type=resultdata['items'][i]['type'] |
type=resultdata['items'][i]['type'] |
||||
|
|
||||
if type=="user": |
if type=="user": |
||||
reqval="/preferences/preferences/"+ id +"/" + preferenceID |
reqval="/preferences/preferences/"+ id +"/" + preferenceID |
||||
result=callrestapi(reqval, reqtype,data=json,stoponerror=0) |
result=callrestapi(reqval, reqtype,data=json,stoponerror=0) |
||||
print(result) |
print(result) |
||||
print("Updating Preference "+reqval+" = "+preferenceValue) |
print("Updating Preference "+reqval+" = "+preferenceValue) |
||||
else: print("Cannot set preferences for a group "+id ) |
else: print("Cannot set preferences for a group "+id ) |
||||
Loading…
Reference in new issue