diff --git a/README.md b/README.md index 04a8f52..fe4c678 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ ### NetBackup API Code Samples -Contains code samples to invoke NetBackup REST API using different programming languages. +Contains code samples of using NetBackup REST APIs in different scripting/programming languages. -#### Disclaimer -These scripts are only meant to be used as a reference. Please do not use these in production. +##### Disclaimer +These samples are only meant to be used as a reference. Please do not use these in production. -#### Executing the snippets for different programming languages +##### Executing the 'snippets' -The `snippets` folder contains code samples to invoke NetBackup REST API using different programming languages. +The `snippets` folder contains code samples to invoke NetBackup APIs using different scripting/programming languages. +These are usually simple examples that demonstrate specific API. Pre-requisites: @@ -15,9 +16,10 @@ Pre-requisites: - See the script's README for the corresponding requirements and usage -#### Executing the recipes for different programming languages +##### Executing the 'recipes' -The `recipes` folder contains code samples to invoke NetBackup REST API using different programming languages. +The `recipes` folder contains code samples to invoke NetBackup APIs using different scripting/programming languages. +These are usually examples of usage of multiple APIs covering specific use-cases. Pre-requisites: @@ -26,8 +28,29 @@ Pre-requisites: -#### Tools -The `tools` folder contains utilities that have proven useful in the development of projects using -NetBackup REST APIs, but do not provide any API usage examples. Again, these tools are not for -production use, but they may be of some use in your work. +##### Tools +The `tools` folder contains utilities that have proven useful in the development of projects using NetBackup APIs, but do not provide any API usage examples. Again, these tools are not for production use, but they may be of some use in your work. +#### NetBackup 8.3 RBAC Design Shift +NetBackup 8.3 introduced a major change in its RBAC configuration and enforcement design. + +RBAC was introduced to NetBackup in the 8.1.2 release, offering access control for a limited number of security settings and workloads. That access control configuration was based on a dynamic object-level enforcement model using “Access Rules”. + +With the NetBackup 8.3 release, RBAC has moved away from the dynamic access rule design. +The new RBAC allows more granular permissions, improved flexibility and greater control. The RBAC design is now based on Access Control Lists (ACLs) and closely follows the ANSI INCITS 359-2004. While the earlier design of RBAC enforcement was dynamic in nature, the new RBAC is static in its configuration. + +The system-defined roles shipped with NetBackup also changed from 8.1.2 to the 8.3 release. In 8.1.2, there were three system-defined roles available for RBAC configuration. In the 8.3 release, this was simplified to offer a single “Administrator” role which has all privileges for RBAC. + +Due to the significant design shift, automatic upgrade conversion of 8.1.2 RBAC roles to the new 8.3 roles is not feasible. However, tools are available to migrate the Backup administrator role and create a new Security administrator role for the users that had the old RBAC Security administrator role. +Other roles must be reconfigured manually. +There is also a script in this repository available to generate templated NetBackup roles. +See **/recipes/perl/access-control/rbac_role_templates.pl** + + +Any API keys in use prior to upgrade will still be valid, however, the underlying access granted those API keys must + be reconfigured using the new RBAC configuration, after which any active user sessions must be removed. +A utility script exists in this repository to help convert active API keys after upgrade to NetBackup 8.3. +See **/recipes/perl/access-control/access_control_api_requests.pl** + +Most of the API examples in this repository assume a valid JWT (Json Web Token) or API Key issued by NetBackup and do + not incorporate role configuration as part of the script. However, there may be some examples which do configure RBAC as part of the script and have not yet been updated to use the RBAC design. diff --git a/recipes/go/admin/README.md b/recipes/go/admin/README.md new file mode 100755 index 0000000..2ebaae5 --- /dev/null +++ b/recipes/go/admin/README.md @@ -0,0 +1,18 @@ +### NetBackup API Code Samples for go (often referred to as golang) + +This directory contains code samples to invoke NetBackup administration REST APIs using go. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher +- go1.10.2 or higher + +#### Executing the recipes using go + +Use the following commands to run the go samples. +- `go run ./get_processes.go -nbmaster -username -password [-domainName ] [-domainType ] -client ` +- `go run ./get_services.go -nbmaster -username -password [-domainName ] [-domainType ] -client ` diff --git a/recipes/go/admin/get_processes.go b/recipes/go/admin/get_processes.go new file mode 100755 index 0000000..5b98854 --- /dev/null +++ b/recipes/go/admin/get_processes.go @@ -0,0 +1,56 @@ +//This script can be run using NetBackup 8.2 and higher. +//It gets all NetBackup processes running on the given host. + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "apihelper" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") + client = flag.String("client", "", "NetBackup host name") +) + +const usage = "\n\nUsage: go run ./get_processes.go -nbmaster -username -password [-domainName ] [-domainType ] -client \n\n" + +func main() { + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + if len(*client) == 0 { + log.Fatalf("Please specify the name of a NetBackup host using the -client parameter.\n") + } + + httpClient := apihelper.GetHTTPClient() + jwt := apihelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + hostUuid := apihelper.GetHostUUID(*nbmaster, httpClient, jwt, *client); + filter := ""; + apihelper.GetProcesses(*nbmaster, httpClient, jwt, *client, hostUuid, filter); +} diff --git a/recipes/go/admin/get_services.go b/recipes/go/admin/get_services.go new file mode 100755 index 0000000..6dc0f2c --- /dev/null +++ b/recipes/go/admin/get_services.go @@ -0,0 +1,55 @@ +//This script can be run using NetBackup 8.2 and higher. +//It gets all NetBackup services available on the given host. + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "apihelper" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") + client = flag.String("client", "", "NetBackup host name") +) + +const usage = "\n\nUsage: go run ./get_services.go -nbmaster -username -password [-domainName ] [-domainType ] -client \n\n" + +func main() { + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + if len(*client) == 0 { + log.Fatalf("Please specify the name of a NetBackup host using the -client parameter.\n") + } + + httpClient := apihelper.GetHTTPClient() + jwt := apihelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + hostUuid := apihelper.GetHostUUID(*nbmaster, httpClient, jwt, *client); + apihelper.GetServices(*nbmaster, httpClient, jwt, *client, hostUuid); +} diff --git a/recipes/go/assets/README.md b/recipes/go/assets/README.md new file mode 100644 index 0000000..d4e173c --- /dev/null +++ b/recipes/go/assets/README.md @@ -0,0 +1,27 @@ +### NetBackup API Code Samples in go + +This directory contains code samples in golang for NetBackup Asset Service APIs. + +#### Disclaimer + +The scripts are provided only for reference and not meant for production use. + +#### Pre-requisites: + +- NetBackup 8.3 or higher +- go1.10.2 or higher + +#### Executing the script + +- get_vmware_assets: + `go run ./get_vmware_assets.go -nbserver -username -password [-domainName ] [-domainType ] [-assetsFilter ]` + + The script invokes the NetBackup VMware Asset Service API to get the VMware workload assets (filtered by the given filter criteria if specified). It prints the asset details (delimited by tab) such as asset display name, instance Id, vCenter and the protection plan names that the asset is protected by. + + Note: The _assetsFilter_ option can be used to filter the assets returned. It should be in OData format (refer to the NetBackup API documentation for more details). It is optional; if not specified the script will return all VM assets. Redirect the script output to a file to avoid printing the details on terminal. + + Examples: + + - List all VMs: `go run ./get_vmware_assets.go -nbserver localhost -username user -password password -domainName domain -domainType NT > vm_assets.txt` + + - List VMs with filter condition: `go run ./get_vmware_assets.go -nbserver localhost -username user -password password -domainName domain -domainType NT -assetsFilter "contains(commonAssetAttributes/displayName, 'backup')"` diff --git a/recipes/go/assets/get_vmware_assets.go b/recipes/go/assets/get_vmware_assets.go new file mode 100755 index 0000000..bea6dc8 --- /dev/null +++ b/recipes/go/assets/get_vmware_assets.go @@ -0,0 +1,136 @@ +//This script can be run using NetBackup 8.3 and higher. +//It gets the list of VMware assets in NetBackup (based on the given filter if specified, else returns all the VMware assets). + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "strconv" + "net/url" + "net/http" + "io/ioutil" + "encoding/json" + "utils" +) + +var ( + nbserver = flag.String("nbserver", "", "NetBackup Server") + username = flag.String("username", "", "User name for NetBackup API login") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name") + domainType = flag.String("domainType", "", "Domain type") + assetsFilter = flag.String("assetsFilter", "", "Filter string (odata format) to filter the assets") +) + +const usage = "\n\nUsage: go run ./get_vmware_assets.go -nbserver -username -password [-domainName ] [-domainType ] [-assetsFilter ]\n\n" + +func main() { + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbserver) == 0 { + log.Fatalf("Please specify the name of the NetBackup Server using the -nbserver option.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username option.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password option.\n") + } + + httpClient := apihelper.GetHTTPClient() + jwt := apihelper.Login(*nbserver, httpClient, *username, *password, *domainName, *domainType) + + vmwareAssetsApiUrl := "https://" + *nbserver + "/netbackup/asset-service/workloads/vmware/assets" + defaultSort := "commonAssetAttributes.displayName" + assetTypeFilter := "(assetType eq 'vm')" + + req, err := http.NewRequest("GET", vmwareAssetsApiUrl, nil) + + if err != nil { + fmt.Printf("Making new HTTP request failed with error: %s\n", err) + panic("Script failed.") + } + + req.Header.Add("Authorization", jwt) + pageLimit := 100 + offset := 0 + next := true + params := url.Values{} + + if assetsFilter != nil { + filter := "" + if *assetsFilter != "" { + filter = *assetsFilter + " and " + assetTypeFilter + } else { + filter = assetTypeFilter + } + params.Add("filter", filter) + } + + params.Add("sort", defaultSort) + params.Add("page[offset]", strconv.Itoa(offset)) + params.Add("page[limit]", strconv.Itoa(pageLimit)) + + fmt.Println("\nGetting VMware assets...") + fmt.Println("Printing the following asset details: Display Name, VM InstanceId, vCenter, Protection Plan Names\n") + + for next { + req.URL.RawQuery = params.Encode() + resp, err := httpClient.Do(req) + + if err != nil { + fmt.Printf("Get VMware Assets failed with error: %s\n", err) + panic("Script failed.") + } else { + respJson, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode == 200 { + var respPayload interface{} + json.Unmarshal(respJson, &respPayload) + respData := respPayload.(map[string]interface{}) + assetsData := respData["data"].([]interface{}) + printAssetDetails(assetsData) + next = respData["meta"].(map[string]interface{})["pagination"]. + (map[string]interface{})["hasNext"].(bool) + } else { + fmt.Println(string(respJson)) + next = false + } + } + offset, _ = strconv.Atoi(params["page[offset]"][0]) + params["page[offset]"][0] = strconv.Itoa(offset + pageLimit) + } + + fmt.Println("\nScript completed.\n") +} + +func printAssetDetails(assets []interface{}) { + for _, asset := range assets { + assetAttrs := asset.(map[string]interface{})["attributes"].(map[string]interface{}) + assetCommonAttrs := assetAttrs["commonAssetAttributes"].(map[string]interface{}) + displayName := assetCommonAttrs["displayName"] + instanceId := assetAttrs["instanceUuid"] + vCenter := assetAttrs["vCenter"] + + var protectionPlans []string + if activeProtections, protected := assetCommonAttrs["activeProtection"]; protected { + protectionDetailsList := activeProtections.(map[string]interface{})["protectionDetailsList"].([]interface{}) + + for _, protectionDetails := range protectionDetailsList { + protectionPlans = append(protectionPlans, protectionDetails. + (map[string]interface{})["protectionPlanName"].(string)) + } + } + fmt.Printf("%s\t%s\t%s\t%v\n", displayName, instanceId, vCenter, protectionPlans) + } + +} diff --git a/recipes/go/config/README.md b/recipes/go/config/README.md new file mode 100755 index 0000000..ada5355 --- /dev/null +++ b/recipes/go/config/README.md @@ -0,0 +1,18 @@ +### NetBackup API Code Samples for go (often referred to as golang) + +This directory contains code samples to invoke NetBackup configuration REST APIs using go. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher +- go1.10.2 or higher + +#### Executing the recipes using go + +Use the following commands to run the go samples. +- `go run ./get_set_host_config.go -nbmaster -username -password [-domainName ] [-domainType ] -client ` +- `go run ./manage_access_hosts.go -nbmaster -username -password [-domainName ] [-domainType ] [-accessHost ]` diff --git a/recipes/go/config/get_set_host_config.go b/recipes/go/config/get_set_host_config.go new file mode 100755 index 0000000..4135a47 --- /dev/null +++ b/recipes/go/config/get_set_host_config.go @@ -0,0 +1,57 @@ +//This script can be run using NetBackup 8.2 and higher. +//It sets exclude list for the given host and reads exclude list to confirm the value was set correctly. + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "apihelper" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") + client = flag.String("client", "", "NetBackup host name") +) + +const usage = "\n\nUsage: go run ./get_set_host_config.go -nbmaster -username -password [-domainName ] [-domainType ] -client \n\n" + +func main() { + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + if len(*client) == 0 { + log.Fatalf("Please specify the name of a NetBackup host using the -client parameter.\n") + } + + httpClient := apihelper.GetHTTPClient() + jwt := apihelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + hostUuid := apihelper.GetHostUUID(*nbmaster, httpClient, jwt, *client); + apihelper.GetExcludeLists(*nbmaster, httpClient, jwt, hostUuid); + apihelper.SetExcludeLists(*nbmaster, httpClient, jwt, hostUuid); + apihelper.GetExcludeLists(*nbmaster, httpClient, jwt, hostUuid); +} diff --git a/recipes/go/config/manage_access_hosts.go b/recipes/go/config/manage_access_hosts.go new file mode 100644 index 0000000..96361a6 --- /dev/null +++ b/recipes/go/config/manage_access_hosts.go @@ -0,0 +1,224 @@ +//This script can be run using NetBackup 8.2 and higher. + +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/http/httputil" + "os" + "apihelper" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") + accessHost = flag.String("accessHost", "dummy.access.host", "Access Host used for demonstration") +) + +//################### +// Global Constants +//################### +const ( + baseUrl = "https://%s:1556/netbackup" + accessHostsUri = "/config/%s/access-hosts" + contentTypeV3 = "application/vnd.netbackup+json;version=3.0" + authorizationHeader = "Authorization" + contentTypeHeader = "Content-Type" + acceptHeader = "Accept" + + usage = "\n\nUsage: go run ./manage_access_hosts.go [-nbmaster ] -username -password [-domainName ] [-domainType ] [-accessHost ]\n\n" + workload = "vmware" +) + +func main() { + flag.Usage = func() { + fmt.Println(usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + if len(*accessHost) == 0 { + log.Println("-accessHost parameter not specified in the command line. Defaulting to 'dummy.access.host'.\n") + } + + httpClient := apihelper.GetHTTPClient() + jwt := apihelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + + // Prints all the access hosts configured on the master server + fmt.Println("Use-case 1\n==========\nReading all the configured access hosts.") + getAllAccessHosts(httpClient, jwt) + fmt.Println("\n\n") + + // Add the provided access host to the list of access hosts + fmt.Println("Use-case 2\n==========\nAdding a new access host.") + addAccessHost(httpClient, jwt) + fmt.Println("\n\n") + + // Get access hosts of type 'CLIENT' + fmt.Println("Use-case 3\n==========\nReading 'CLIENT' type access hosts.") + getAccessHostsOfSpecificType("CLIENT", httpClient, jwt) + fmt.Println("\n\n") + + // Delete the recently added access host + fmt.Println("Use-case 4\n==========\nDeleting the dummy access host.") + deleteAccessHost(httpClient, jwt) + fmt.Println("\n\n") + + // Prints all the access hosts configured on the master server + fmt.Println("Use-case 5\n==========\nReading all the configured access hosts.") + getAllAccessHosts(httpClient, jwt) + fmt.Println("\n\n") +} + +func getAllAccessHosts(httpClient *http.Client, jwt string) { + fmt.Println("Workload: " + workload +"\t\tMaster Server: " + *nbmaster) + apiResponse := getAccessHosts(httpClient, jwt, "") + printAccessHostsResponse(apiResponse) +} + +func getAccessHostsOfSpecificType(hostType string, httpClient *http.Client, jwt string) { + fmt.Println("Workload: " + workload +"\tHost Type: " + hostType + "\tMaster Server: " + *nbmaster) + filter := "hostType eq '" + hostType + "'" + apiResponse := getAccessHosts(httpClient, jwt, filter) + printAccessHostsResponse(apiResponse) +} + +func getAccessHosts(httpClient *http.Client, jwt string, filter string) []byte { + apiUrl := fmt.Sprintf(baseUrl, *nbmaster) + fmt.Sprintf(accessHostsUri, workload) + + request, _ := http.NewRequest(http.MethodGet, apiUrl, nil) + request.Header.Add(authorizationHeader, jwt) + request.Header.Add(acceptHeader, contentTypeV3) + if filter != "" { + query := request.URL.Query() + query.Add("filter", filter) + request.URL.RawQuery = query.Encode() + } + + response, err := httpClient.Do(request) + var emptyByte []byte + + if err != nil { + fmt.Println("The HTTP request failed with error: %s\n", err) + panic("Unable to read access hosts for the master server: " + *nbmaster) + } else { + if response.StatusCode != http.StatusOK { + printErrorResponse(response) + } else { + resp, _ := ioutil.ReadAll(response.Body) + return resp + } + } + return emptyByte +} + +func addAccessHost(httpClient *http.Client, jwt string) { + fmt.Println("Adding access host: " + *accessHost) + apiUrl := fmt.Sprintf(baseUrl, *nbmaster) + fmt.Sprintf(accessHostsUri, workload) + + accessHostRequest := map[string]interface{}{ + "data": map[string]interface{}{ + "type": "accessHostRequest", + "id": workload, + "attributes": map[string]interface{}{ + "hostname": *accessHost, + "validate": false}}} + + accessHostRequestBody, _ := json.Marshal(accessHostRequest) + + request, _ := http.NewRequest(http.MethodPost, apiUrl, bytes.NewBuffer(accessHostRequestBody)) + request.Header.Add(authorizationHeader, jwt) + request.Header.Add(contentTypeHeader, contentTypeV3) + + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to add access host for workload '" + workload + "' on master '" + *nbmaster +"'\n") + } else { + if response.StatusCode != 204 { + printErrorResponse(response) + } else { + fmt.Printf("Access Host '%s' added successfully.\n", *accessHost); + } + } +} + +func deleteAccessHost(httpClient *http.Client, jwt string) { + fmt.Println("Deleting access host: " + *accessHost) + apiUrl := fmt.Sprintf(baseUrl, *nbmaster) + fmt.Sprintf(accessHostsUri, workload) + "/" + *accessHost + + request, _ := http.NewRequest(http.MethodDelete, apiUrl, nil) + request.Header.Add(authorizationHeader, jwt) + request.Header.Add(acceptHeader, contentTypeV3) + + response, err := httpClient.Do(request) + + if err != nil { + fmt.Println("The HTTP request failed with error: %s\n", err) + panic("Unable to delete access host for the master server: " + *nbmaster) + } else { + if response.StatusCode != http.StatusNoContent { + printErrorResponse(response) + } else { + fmt.Printf("Access Host '%s' deleted successfully.", *accessHost) + } + } +} + +func printErrorResponse(response *http.Response) { + responseBody, _ := ioutil.ReadAll(response.Body) + var obj interface{} + json.Unmarshal(responseBody, &obj) + + if obj != nil { + error := obj.(map[string]interface{}) + errorCode := error["errorCode"].(float64) + errorMessage := error["errorMessage"].(string) + fmt.Printf("Error code:%.0f\nError message:%s\n", errorCode, errorMessage) + } else { + responseDetails, _ := httputil.DumpResponse(response, true); + fmt.Printf(string(responseDetails)) + } + + panic("Request failed"); +} + +func printAccessHostsResponse(apiResponse []byte) { + var obj interface{} + json.Unmarshal([]byte(apiResponse), &obj) + data := obj.(map[string]interface{}) + var accessHosts []interface{} = data["data"].([]interface{}) + fmt.Println(" Host Type Workload Hostname") + fmt.Println("===============.===============.=========================") + for _, host := range accessHosts { + hostName := (host.(map[string]interface{}))["id"] + attributes := ((host.(map[string]interface{}))["attributes"]).(map[string]interface{}) + respWorkload := attributes["workloadType"] + respHostType := attributes["hostType"] + fmt.Printf("%15s %15s %25s\n", respHostType, respWorkload, hostName) + } +} diff --git a/recipes/go/images/README.md b/recipes/go/images/README.md new file mode 100644 index 0000000..4a6fa5a --- /dev/null +++ b/recipes/go/images/README.md @@ -0,0 +1,21 @@ +### NetBackup API Code Samples for go (often referred to as golang) + +This directory contains code samples to invoke NetBackup Catalog (Image) APIs using go. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- Image update related API samples will work on NetBackup 8.2 or higher. +- go1.10.2 or higher + +#### Executing the recipes using go + +Use the following commands to run the go samples. +- The following assumes you set MASTERSERVER, USERID,PASSWORD, backupID, serverName, serverType and optionValue in your environment. +- `go run ./update_nb_images.go -nbmaster ${MASTERSERVER} -username ${USERID} -password ${PASSWORD} -backupId ${backupID}` +- `go run ./update_nb_images_by_server_name.go -nbmaster ${MASTERSERVER} -username ${USERID} -password ${PASSWORD} -serverName ${serverName}` +- `go run ./update_nb_images_by_server_type.go -nbmaster ${MASTERSERVER} -username ${USERID} -password ${PASSWORD} -serverType ${serverType}` +- `go run ./update_nb_images_primary_copy.go -nbmaster ${MASTERSERVER} -username ${USERID} -password ${PASSWORD} -optionValue ${optionValue}` diff --git a/recipes/go/images/update_nb_images.go b/recipes/go/images/update_nb_images.go new file mode 100644 index 0000000..4aa3f88 --- /dev/null +++ b/recipes/go/images/update_nb_images.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "flag" + "log" + "os" + "apihelper" + "images" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") + backupId = flag.String ("backupId","", "BackupId of the image for which expiration date needs update.") +) + + + + +const usage = "\n\nUsage: go run ./update_nb_images.go -nbmaster -username -password [-domainName ] [-domainType ] -backupId n\n" + +func main() { + + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + + if len(*backupId) == 0 { + log.Fatalf("Please specify the backupId using the -backupId parameter.\n") + } + + httpClient := apihelper.GetHTTPClient() + token := apihelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + + images.UpdateImageExpirationDateByBackupId ( httpClient, *nbmaster, token, *backupId ) + images.UpdateImageExpirationDateByRecalculating ( httpClient, *nbmaster, token, *backupId ) +} diff --git a/recipes/go/images/update_nb_images_by_server_name.go b/recipes/go/images/update_nb_images_by_server_name.go new file mode 100644 index 0000000..ce98fb1 --- /dev/null +++ b/recipes/go/images/update_nb_images_by_server_name.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "flag" + "log" + "os" + "apihelper" + "images" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") + serverName = flag.String ("serverName","", "Server name for the image to which expiration date needs update.") +) + + + +const usage = "\n\nUsage: go run ./update_nb_images_by_server_name.go -nbmaster -username -password [-domainName ] [-domainType ] -serverName n\n" + +func main() { + + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + + if len(*serverName) == 0 { + log.Fatalf("Please specify the serverName using the -serverName parameter.\n") + } + + httpClient := apihelper.GetHTTPClient() + token := apihelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + + images.UpdateImageExpirationDateByServerName ( httpClient, *nbmaster, token, *serverName ) + +} diff --git a/recipes/go/images/update_nb_images_by_server_type.go b/recipes/go/images/update_nb_images_by_server_type.go new file mode 100644 index 0000000..c5b6ff5 --- /dev/null +++ b/recipes/go/images/update_nb_images_by_server_type.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "flag" + "log" + "os" + "apihelper" + "images" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") + serverType = flag.String ("serverType","", "Server type for the image to which expiration date needs update.") +) + + + +const usage = "\n\nUsage: go run ./update_nb_images_by_server_type.go -nbmaster -username -password [-domainName ] [-domainType ] -serverType n\n" + +func main() { + + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + + if len(*serverType) == 0 { + log.Fatalf("Please specify the serverName using the -serverType parameter.\n") + } + + httpClient := apihelper.GetHTTPClient() + token := apihelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + + images.UpdateImageExpirationDateByServerType ( httpClient, *nbmaster, token, *serverType ) + +} diff --git a/recipes/go/images/update_nb_images_primary_copy.go b/recipes/go/images/update_nb_images_primary_copy.go new file mode 100644 index 0000000..ffa42c0 --- /dev/null +++ b/recipes/go/images/update_nb_images_primary_copy.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "flag" + "log" + "os" + "apihelper" + "images" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") + optionValue = flag.String ("optionValue","", "The option value for updating primary copy of images.") +) + + + +const usage = "\n\nUsage: go run ./update_nb_images_primary_copy.go -nbmaster -username -password [-domainName ] [-domainType ] -optionValue n\n" + +func main() { + + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + + if len(*optionValue) == 0 { + log.Fatalf("Please specify the optionValue using the -optionValue parameter.\n") + } + + httpClient := apihelper.GetHTTPClient() + token := apihelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + + images.UpdateImagePrimaryCopy ( httpClient, *nbmaster, token, *optionValue ) + +} diff --git a/recipes/go/README.md b/recipes/go/policies/README.md old mode 100644 new mode 100755 similarity index 87% rename from recipes/go/README.md rename to recipes/go/policies/README.md index 8207c5b..d91996b --- a/recipes/go/README.md +++ b/recipes/go/policies/README.md @@ -1,6 +1,6 @@ ### NetBackup API Code Samples for go (often referred to as golang) -This directory contains code samples to invoke NetBackup REST APIs using go. +This directory contains code samples to invoke NetBackup policies REST APIs using go. #### Disclaimer diff --git a/recipes/go/create_policy_in_one_step.go b/recipes/go/policies/create_policy_in_one_step.go similarity index 96% rename from recipes/go/create_policy_in_one_step.go rename to recipes/go/policies/create_policy_in_one_step.go index ce5a5c6..4356ebe 100644 --- a/recipes/go/create_policy_in_one_step.go +++ b/recipes/go/policies/create_policy_in_one_step.go @@ -9,7 +9,7 @@ import ( "fmt" "log" "os" - "policies/apihelper" + "apihelper" ) //################### diff --git a/recipes/go/create_policy_step_by_step.go b/recipes/go/policies/create_policy_step_by_step.go similarity index 96% rename from recipes/go/create_policy_step_by_step.go rename to recipes/go/policies/create_policy_step_by_step.go index f233947..2882ef4 100644 --- a/recipes/go/create_policy_step_by_step.go +++ b/recipes/go/policies/create_policy_step_by_step.go @@ -9,7 +9,7 @@ import ( "fmt" "log" "os" - "policies/apihelper" + "apihelper" ) //################### diff --git a/recipes/go/storage/AIRAPIs/AIRAPIs.go b/recipes/go/storage/AIRAPIs/AIRAPIs.go new file mode 100644 index 0000000..deac305 --- /dev/null +++ b/recipes/go/storage/AIRAPIs/AIRAPIs.go @@ -0,0 +1,70 @@ +//This script can be run using NetBackup 8.2 and higher. + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "storageHelper" +) + +//################### +// Global Variables +//################### +var ( + nbmaster = flag.String("nbmaster", "", "NetBackup Master Server") + username = flag.String("username", "", "User name to log into the NetBackup webservices") + password = flag.String("password", "", "Password for the given user") + domainName = flag.String("domainName", "", "Domain name of the given user") + domainType = flag.String("domainType", "", "Domain type of the given user") +) + +const usage = "\n\nUsage: go run ./AIRAPIs.go -nbmaster -username -password [-domainName ] [-domainType ]\n\n" + +func main() { + // Print usage + flag.Usage = func() { + fmt.Fprintf(os.Stderr, usage) + os.Exit(1) + } + + // Read command line arguments + flag.Parse() + + if len(*nbmaster) == 0 { + log.Fatalf("Please specify the name of the NetBackup Master Server using the -nbmaster parameter.\n") + } + if len(*username) == 0 { + log.Fatalf("Please specify the username using the -username parameter.\n") + } + if len(*password) == 0 { + log.Fatalf("Please specify the password using the -password parameter.\n") + } + + httpClient := storageHelper.GetHTTPClient() + jwt := storageHelper.Login(*nbmaster, httpClient, *username, *password, *domainName, *domainType) + + status, stsName := storageHelper.CreateMSDPStorageServer(*nbmaster, httpClient, jwt) + if( status != 201){ + panic("CreateMSDPStorageServer Failed. Exiting.\n") + } + + candInx, candId := storageHelper.GetReplicationCandidates(*nbmaster, httpClient, jwt) + if ( candInx == 0 ) { + fmt.Println("Exiting") + os.Exit(0) + } + + if ( storageHelper.AddReplicationTarget(*nbmaster, httpClient, jwt, stsName, candId) != 201 ) { + panic("AddReplicationTarget Failed. Exiting.\n") + } + + tarInx, tarId := storageHelper.GetReplicationTargets(*nbmaster, httpClient, jwt, stsName) + if ( tarInx == 0 ) { + fmt.Println("Exiting") + os.Exit(0) + } + storageHelper.DeleteReplicationTargets(*nbmaster, httpClient, jwt, stsName, tarId) +} diff --git a/recipes/go/storage/ApiUtil/ApiUtil.go b/recipes/go/storage/ApiUtil/ApiUtil.go new file mode 100644 index 0000000..1f49960 --- /dev/null +++ b/recipes/go/storage/ApiUtil/ApiUtil.go @@ -0,0 +1,51 @@ +//This script consists of the helper functions to read and process user inpus + +package apiUtil + +import ( + "bufio" + "os" + "strings" + "io" + "fmt" + "bytes" +) + +func TakeInput(displayStr string)(string) { + + reader := bufio.NewReader(os.Stdin) + fmt.Print(displayStr) + output, _ := reader.ReadString('\n') + // convert CRLF to LF + output = strings.Replace(output, "\r\n", "", -1) + output = strings.Replace(output, "\n", "", -1) + return output +} + +func AskForResponseDisplay(response io.ReadCloser) { + if strings.Compare(TakeInput("Show response? (Yes/No)"), "Yes") == 0 { + buf := new(bytes.Buffer) + buf.ReadFrom(response) + responseStr := buf.String() + responseStr = strings.Replace(responseStr, "}", "}\r\n", -1) + responseStr = strings.Replace(responseStr, ",", ",\r\n", -1) + responseStr = strings.Replace(responseStr, "]", "]\r\n", -1) + + fmt.Print(responseStr) + } else { + fmt.Println("Response is not Yes!!") + } +} + +func AskForGETResponseDisplay(response []byte) { + if strings.Compare(TakeInput("Show response? (Yes/No)"), "Yes") == 0 { + responseStr := string(response) + responseStr = strings.Replace(responseStr, "}", "}\r\n", -1) + responseStr = strings.Replace(responseStr, ",", ",\r\n", -1) + responseStr = strings.Replace(responseStr, "]", "]\r\n", -1) + + fmt.Print(responseStr) + } else { + fmt.Println("Response is not Yes!!") + } +} \ No newline at end of file diff --git a/recipes/go/storage/README.txt b/recipes/go/storage/README.txt new file mode 100644 index 0000000..b76e2a8 --- /dev/null +++ b/recipes/go/storage/README.txt @@ -0,0 +1,15 @@ +Run the AIRAPIs.go file using Go. + +Prerequisites +1. Atleast a couple of NBU master servers. +2. MSDP or CC storage server created on one of them. (Use the nbmaster as the other master server for the script execution) +3. Trust relationship established between the two NBU masters. + +Run cli in AIRAPIs directory +Go run AIRAPIs.go -nbmaster -username -password + +The script can also create new MSDP storage server (with creds as a/a) depending on user inputs. +Further lists the replication candidates based on the no of trusted master servers and storage server (MSDP and CC) on them. +User need to select one of the replication candidate to create AIR relationship on the earlier created MSDP/CC sts or existing one. +User can delete any existing AIR relationship as well. + diff --git a/recipes/go/storage/StorageHelper/StorageHelper.go b/recipes/go/storage/StorageHelper/StorageHelper.go new file mode 100644 index 0000000..1e25a6c --- /dev/null +++ b/recipes/go/storage/StorageHelper/StorageHelper.go @@ -0,0 +1,381 @@ +//This script consists of the helper functions to excute NetBackup APIs to assist in Air operation for MSDP sts + +// 1. Get the HTTP client to perform API requests +// 2. Login to the NetBackup webservices +// 3. Create MSDP storage server +// 4. Get Replication candidates +// 5. Add Replication target +// 6. Get Replication targets +// 7. Delete Replication target + +package storageHelper + +import ( + "bufio" + "os" + "strings" + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "apiUtil" +) + +type Data struct { + id string `json:"id"` + apiType string `json:"type"` + attr interface{} `json:"attributes"` +} + +type DataArray struct { + dataList []Data `json:"data"` +} + + +//################### +// Global Variables +//################### + +var mediaServerName string +const ( + port = "1556" + storageUri = "storage/" + storageServerUri = "storage-servers/" + storageUnitUri = "storage-units" + contentType = "application/vnd.netbackup+json;version=3.0" + replicationTargetsUri = "/replication-targets" + replicationCandidatesUri = "/target-storage-servers" +) + +//############################################################## +// Setup the HTTP client to make NetBackup Storage API requests +//############################################################## +func GetHTTPClient() *http.Client { + tlsConfig := &tls.Config { + InsecureSkipVerify: true, //for this test, ignore ssl certificate + } + + tr := &http.Transport{TLSClientConfig: tlsConfig} + client := &http.Client{Transport: tr} + + return client +} + +//##################################### +// Login to the NetBackup webservices +//##################################### +func Login(nbmaster string, httpClient *http.Client, username string, password string, domainName string, domainType string) string { + fmt.Printf("\nLogin to the NetBackup webservices...\n") + + loginDetails := map[string]string{"userName": username, "password": password} + if len(domainName) > 0 { + loginDetails["domainName"] = domainName + } + if len(domainType) > 0 { + loginDetails["domainType"] = domainType + } + loginRequest, _ := json.Marshal(loginDetails) + + uri := "https://" + nbmaster + ":" + port + "/netbackup/login" + + request, _ := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(loginRequest)) + request.Header.Add("Content-Type", contentType); + + response, err := httpClient.Do(request) + + token := "" + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to login to the NetBackup webservices") + } else { + if response.StatusCode == 201 { + data, _ := ioutil.ReadAll(response.Body) + var obj interface{} + json.Unmarshal(data, &obj) + loginResponse := obj.(map[string]interface{}) + token = loginResponse["token"].(string) + } else { + responseBody, _ := ioutil.ReadAll(response.Body) + fmt.Printf("%s\n", responseBody) + panic("Unable to login to the NetBackup webservices") + } + } + + return token +} + +//####################################################################### +// Create a MSDP Storage server +//####################################################################### +func CreateMSDPStorageServer(nbmaster string, httpClient *http.Client, jwt string)(int, string) { + fmt.Printf("\nSending a POST request to create with defaults...\n") + if strings.Compare(apiUtil.TakeInput("Want to create new MSDP storage server?(Or you can use existing)(Yes/No):"), "Yes") != 0 { + stsName := apiUtil.TakeInput("Enter MSDP/CloudCatalyst Storage Server Name for other operations:") + return 201, stsName; + } + + stsName := apiUtil.TakeInput("Enter Storage/Media Server Name:") + mediaServerName = stsName + + storagePath := apiUtil.TakeInput("Enter Storage Path:") + + MSDPstorageServer := map[string]interface{}{ + "data": map[string]interface{}{ + "type": "storageServer", + "id": stsName, + "attributes": map[string]interface{}{ + "name":stsName, + "storageCategory":"MSDP", + "mediaServerDetails": map[string]interface{}{ + "name": mediaServerName}, + "msdpAttributes": map[string]interface{}{ + "storagePath": storagePath, + "credentials":map[string]interface{}{ + "userName": "a", + "password": "a"}}}}} + + + + stsRequest, _ := json.Marshal(MSDPstorageServer) + + uri := "https://" + nbmaster + ":" + port + "/netbackup/" + storageUri + storageServerUri + + request, _ := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(stsRequest)) + request.Header.Add("Content-Type", contentType); + request.Header.Add("Authorization", jwt); + + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to create storage server.\n") + } else { + if response.StatusCode != 201 { + responseBody, _ := ioutil.ReadAll(response.Body) + fmt.Printf("%s\n", responseBody) + panic("Unable to create MSDP Sts.\n") + } else { + fmt.Printf("%s created successfully.\n", stsName); + //responseDetails, _ := httputil.DumpResponse(response, true); + apiUtil.AskForResponseDisplay(response.Body) + } + } + + return response.StatusCode, mediaServerName; +} + +//####################################################################### +// Get Replication candidates +//####################################################################### +func GetReplicationCandidates(nbmaster string, httpClient *http.Client, jwt string)(int, string) { + fmt.Printf("\nSending a GET request for replication candidates...\n") + + reader := bufio.NewReader(os.Stdin) + var candidateinx int + var candidateID string + uri := "https://" + nbmaster + ":" + port + "/netbackup/" + storageUri + replicationCandidatesUri + + request, _ := http.NewRequest(http.MethodGet, uri, nil) + request.Header.Add("Content-Type", contentType); + request.Header.Add("Authorization", jwt); + + fmt.Println ("Firing request: GET: " + uri) + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to create storage server.\n") + } else { + if response.StatusCode == 200 { + data, _ := ioutil.ReadAll(response.Body) + var obj interface{} + err := json.Unmarshal(data, &obj) + if(err == nil){ + //responseDetails, _ := httputil.DumpResponse(response, true); + apiUtil.AskForGETResponseDisplay(data) + dataArray := obj.(map[string]interface{}) + var dataObj = dataArray["data"].([]interface{}) + addRepTar := apiUtil.TakeInput("Do you want to add replication target?(Yes/No)") + if strings.Compare(addRepTar, "Yes") == 0 { + for i := 0; i < len(dataObj); i++ { + var indobj = dataObj[i].(map[string]interface{}) + candidateID = indobj["id"].(string) + fmt.Printf("%d. %s\n", i+1, candidateID) + } + fmt.Print("Select index of candidate to add as target: ") + loopCont := true + for ok := true; ok; ok = loopCont { + candInx, _ := reader.ReadString('\n') + candInx = strings.Replace(candInx, "\r\n", "", -1) + candInxInt, err := strconv.Atoi(candInx) + if err != nil || candInxInt > len(dataObj) { + fmt.Print("Invalid indexx. Try again. (0 to exit):") + } else { + loopCont = false + candidateinx = candInxInt + } + } + } + } + } else { + responseBody, _ := ioutil.ReadAll(response.Body) + fmt.Printf("%s\n", responseBody) + panic("Failed to successfully execute get replication candidates API ") + } + } + + return candidateinx, candidateID; +} + + +//####################################################################### +// Add replication target to MSDP Sts +//####################################################################### +func AddReplicationTarget(nbmaster string, httpClient *http.Client, jwt string, stsName string, candId string)(int) { + fmt.Printf("\nSending a POST request to create with defaults...\n") + + //reader := bufio.NewReader(os.Stdin) + IdSlice := strings.Split(candId, ":") + + username := apiUtil.TakeInput("Enter target storage server username:") + password := apiUtil.TakeInput("Enter target storage server password:") + + replicationtarget := map[string]interface{}{ + "data": map[string]interface{}{ + "type": "replicationTargetRequest", + "attributes": map[string]interface{}{ + "targetStorageServerInfo": map[string]interface{}{ + "targetMasterServer": IdSlice[3], + "targetStorageServer": IdSlice[1], + "targetStorageServerType": IdSlice[0], + "targetMediaServer": IdSlice[2]}, + "targetStorageServerCredentials": map[string]interface{}{ + "userName": username, + "password": password}}}} + + + + stsRequest, _ := json.Marshal(replicationtarget) + + uri := "https://" + nbmaster + ":" + port + "/netbackup/" + storageUri + storageServerUri + "PureDisk:" + stsName + replicationTargetsUri + + request, _ := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(stsRequest)) + request.Header.Add("Content-Type", contentType); + request.Header.Add("Authorization", jwt); + + fmt.Println ("Firing request: POST: " + uri) + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to add replication target.\n") + } else { + if response.StatusCode != 201 { + responseBody, _ := ioutil.ReadAll(response.Body) + fmt.Printf("%s\n", responseBody) + panic("Unable to add replication target.\n") + } else { + fmt.Printf("%s created successfully.\n", ""); + //responseDetails, _ := httputil.DumpResponse(response, true); + apiUtil.AskForResponseDisplay(response.Body) + } + } + + return response.StatusCode; +} + + +//####################################################################### +// Get Replication targets +//####################################################################### +func GetReplicationTargets(nbmaster string, httpClient *http.Client, jwt string, stsName string)(int, string) { + fmt.Printf("\nSending a GET request for replication targets...\n") + + reader := bufio.NewReader(os.Stdin) + var candidateinx int + var candidateID string + uri := "https://" + nbmaster + ":" + port + "/netbackup/" + storageUri + storageServerUri + "PureDisk:" + stsName + replicationTargetsUri + + request, _ := http.NewRequest(http.MethodGet, uri, nil) + request.Header.Add("Content-Type", contentType); + request.Header.Add("Authorization", jwt); + + fmt.Println ("Firing request: GET: " + uri) + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to create storage server.\n") + } else { + if response.StatusCode == 200 { + data, _ := ioutil.ReadAll(response.Body) + var obj interface{} + err := json.Unmarshal(data, &obj) + if(err == nil){ + dataArray := obj.(map[string]interface{}) + var dataObj = dataArray["data"].([]interface{}) + apiUtil.AskForGETResponseDisplay(data) + delRepTar := apiUtil.TakeInput("Do you want to delete replication target?(Yes/No)") + if strings.Compare(delRepTar, "Yes") == 0 { + for i := 0; i < len(dataObj); i++ { + var indobj = dataObj[i].(map[string]interface{}) + candidateID = indobj["id"].(string) + fmt.Printf("%d. %s\n", i+1, candidateID) + } + fmt.Print("Select index to delete replication target: ") + loopCont := true + for ok := true; ok; ok = loopCont { + candInx, _ := reader.ReadString('\n') + candInx = strings.Replace(candInx, "\r\n", "", -1) + candInxInt, err := strconv.Atoi(candInx) + if err != nil || candInxInt > len(dataObj) { + fmt.Print("InvalidInx. Try again. (0 to exit):") + } else { + loopCont = false + candidateinx = candInxInt + } + } + } + } + } else { + responseBody, _ := ioutil.ReadAll(response.Body) + fmt.Printf("%s\n", responseBody) + panic("Unable to login to the NetBackup webservices") + } + } + return candidateinx, candidateID; +} + + +//####################################################################### +// Delete Replication targets +//####################################################################### +func DeleteReplicationTargets(nbmaster string, httpClient *http.Client, jwt string, stsName string, id string)(int) { + fmt.Printf("\nSending a GET request for replication targets...\n") + + uri := "https://" + nbmaster + ":" + port + "/netbackup/" + storageUri + storageServerUri + "PureDisk:" + stsName + replicationTargetsUri + "/" + id + + request, _ := http.NewRequest(http.MethodDelete, uri, nil) + request.Header.Add("Content-Type", contentType); + request.Header.Add("Authorization", jwt); + + fmt.Println ("Firing request: DELETE: " + uri) + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to delete replication target.\n") + } else { + if response.StatusCode == 204 { + fmt.Printf("Replication Target deleted successfully.\n") + } else { + responseBody, _ := ioutil.ReadAll(response.Body) + fmt.Printf("%s\n", responseBody) + panic("Unable to login to the NetBackup webservices") + } + } + return response.StatusCode; +} diff --git a/recipes/go/policy_api_helper.go b/recipes/go/utils/api_helper.go similarity index 61% rename from recipes/go/policy_api_helper.go rename to recipes/go/utils/api_helper.go index 837fe6d..afdae8a 100644 --- a/recipes/go/policy_api_helper.go +++ b/recipes/go/utils/api_helper.go @@ -1,4 +1,4 @@ -//This script consists of the helper functions to excute NetBackup APIs to assist in policy CRUD operations +//This script consists of the helper functions to excute NetBackup APIs // 1. Get the HTTP client to perform API requests // 2. Login to the NetBackup webservices @@ -12,8 +12,14 @@ // 10. Delete a client // 11. Add/Update backup selection // 12. Delete a policy +// 13. Get exclude list for a host +// 14. Set exclude list for a host +// 15. Get NetBackup processes running on a host +// 16. Get NetBackup processes matching a filter criteria +// 17. Get NetBackup services available on a host +// 18. Get NetBackup service with a name on a host -package helper +package apihelper import ( "bytes" @@ -31,7 +37,8 @@ import ( const ( port = "1556" policiesUri = "config/policies/" - contentType = "application/vnd.netbackup+json;version=2.0" + contentTypeV2 = "application/vnd.netbackup+json;version=2.0" + contentTypeV3 = "application/vnd.netbackup+json;version=3.0" testPolicyName = "vmware_test_policy" testClientName = "MEDIA_SERVER" testScheduleName = "vmware_test_schedule" @@ -55,7 +62,7 @@ func GetHTTPClient() *http.Client { // Login to the NetBackup webservices //##################################### func Login(nbmaster string, httpClient *http.Client, username string, password string, domainName string, domainType string) string { - fmt.Printf("\nLogin to the NetBackup webservices...\n") + fmt.Printf("\nLog into the NetBackup webservices...\n") loginDetails := map[string]string{"userName": username, "password": password} if len(domainName) > 0 { @@ -69,14 +76,14 @@ func Login(nbmaster string, httpClient *http.Client, username string, password s uri := "https://" + nbmaster + ":" + port + "/netbackup/login" request, _ := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(loginRequest)) - request.Header.Add("Content-Type", contentType); + request.Header.Add("Content-Type", contentTypeV2); response, err := httpClient.Do(request) token := "" if err != nil { fmt.Printf("The HTTP request failed with error: %s\n", err) - panic("Unable to login to the NetBackup webservices") + panic("Unable to login to the NetBackup webservices.") } else { if response.StatusCode == 201 { data, _ := ioutil.ReadAll(response.Body) @@ -85,9 +92,7 @@ func Login(nbmaster string, httpClient *http.Client, username string, password s loginResponse := obj.(map[string]interface{}) token = loginResponse["token"].(string) } else { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to login to the NetBackup webservices") + printErrorResponse(response) } } @@ -197,7 +202,7 @@ func CreatePolicy(nbmaster string, httpClient *http.Client, jwt string) { uri := "https://" + nbmaster + ":" + port + "/netbackup/" + policiesUri request, _ := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(policyRequest)) - request.Header.Add("Content-Type", contentType); + request.Header.Add("Content-Type", contentTypeV2); request.Header.Add("Authorization", jwt); request.Header.Add("X-NetBackup-Audit-Reason", "created policy " + testPolicyName); @@ -208,9 +213,7 @@ func CreatePolicy(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to create policy.\n") } else { if response.StatusCode != 204 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to create policy.\n") + printErrorResponse(response) } else { fmt.Printf("%s created successfully.\n", testPolicyName); responseDetails, _ := httputil.DumpResponse(response, true); @@ -244,7 +247,7 @@ func CreatePolicyWithDefaults(nbmaster string, httpClient *http.Client, jwt stri uri := "https://" + nbmaster + ":" + port + "/netbackup/" + policiesUri request, _ := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(policyRequest)) - request.Header.Add("Content-Type", contentType); + request.Header.Add("Content-Type", contentTypeV2); request.Header.Add("Authorization", jwt); response, err := httpClient.Do(request) @@ -254,9 +257,7 @@ func CreatePolicyWithDefaults(nbmaster string, httpClient *http.Client, jwt stri panic("Unable to create policy.\n") } else { if response.StatusCode != 204 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to create policy.\n") + printErrorResponse(response) } else { fmt.Printf("%s created successfully.\n", testPolicyName); responseDetails, _ := httputil.DumpResponse(response, true); @@ -283,9 +284,7 @@ func ListPolicies(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to list policies.\n") } else { if response.StatusCode != 200 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to list policies.\n") + printErrorResponse(response) } else { responseBody, _ := ioutil.ReadAll(response.Body) fmt.Printf("%s\n", responseBody) @@ -311,9 +310,7 @@ func ReadPolicy(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to read policy.\n") } else { if response.StatusCode != 200 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to read policy.\n") + printErrorResponse(response) } else { responseBody, _ := ioutil.ReadAll(response.Body) fmt.Printf("%s\n", responseBody) @@ -339,9 +336,7 @@ func DeletePolicy(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to delete policy.\n") } else { if response.StatusCode != 204 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to delete policy.\n") + printErrorResponse(response) } else { fmt.Printf("%s deleted successfully.\n", testPolicyName); } @@ -367,7 +362,7 @@ func AddClient(nbmaster string, httpClient *http.Client, jwt string) { uri := "https://" + nbmaster + ":" + port + "/netbackup/" + policiesUri + testPolicyName + "/clients/" + testClientName request, _ := http.NewRequest(http.MethodPut, uri, bytes.NewBuffer(clientRequest)) - request.Header.Add("Content-Type", contentType); + request.Header.Add("Content-Type", contentTypeV2); request.Header.Add("Authorization", jwt); request.Header.Add("If-Match", "1"); request.Header.Add("X-NetBackup-Audit-Reason", "added client " + testClientName + " to policy " + testPolicyName); @@ -379,9 +374,7 @@ func AddClient(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to add client to policy.\n") } else { if response.StatusCode != 201 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to add client to policy.\n") + printErrorResponse(response) } else { fmt.Printf("%s added to %s successfully.\n", testClientName, testPolicyName); responseDetails, _ := httputil.DumpResponse(response, true); @@ -408,9 +401,7 @@ func DeleteClient(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to delete client.\n") } else { if response.StatusCode != 204 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to delete client.\n") + printErrorResponse(response) } else { fmt.Printf("%s deleted successfully.\n", testClientName); } @@ -485,7 +476,7 @@ func AddSchedule(nbmaster string, httpClient *http.Client, jwt string) { uri := "https://" + nbmaster + ":" + port + "/netbackup/" + policiesUri + testPolicyName + "/schedules/" + testScheduleName request, _ := http.NewRequest(http.MethodPut, uri, bytes.NewBuffer(scheduleRequest)) - request.Header.Add("Content-Type", contentType); + request.Header.Add("Content-Type", contentTypeV2); request.Header.Add("Authorization", jwt); response, err := httpClient.Do(request) @@ -495,9 +486,7 @@ func AddSchedule(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to add schedule to policy.\n") } else { if response.StatusCode != 201 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to add schedule to policy.\n") + printErrorResponse(response) } else { fmt.Printf("%s added to %s successfully.\n", testScheduleName, testPolicyName); } @@ -522,9 +511,7 @@ func DeleteSchedule(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to delete schedule.\n") } else { if response.StatusCode != 204 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to delete schedule.\n") + printErrorResponse(response) } else { fmt.Printf("%s deleted successfully.\n", testScheduleName); } @@ -548,7 +535,7 @@ func AddBackupSelection(nbmaster string, httpClient *http.Client, jwt string) { uri := "https://" + nbmaster + ":" + port + "/netbackup/" + policiesUri + testPolicyName + "/backupselections" request, _ := http.NewRequest(http.MethodPut, uri, bytes.NewBuffer(bkupSelectionRequest)) - request.Header.Add("Content-Type", contentType); + request.Header.Add("Content-Type", contentTypeV2); request.Header.Add("Authorization", jwt); response, err := httpClient.Do(request) @@ -558,11 +545,283 @@ func AddBackupSelection(nbmaster string, httpClient *http.Client, jwt string) { panic("Unable to add backupselection to policy.\n") } else { if response.StatusCode != 204 { - responseBody, _ := ioutil.ReadAll(response.Body) - fmt.Printf("%s\n", responseBody) - panic("Unable to add backupselection to policy.\n") + printErrorResponse(response) } else { fmt.Printf("backupselection added to %s successfully.\n", testPolicyName); } } } + +//##################################################### +// Get the host UUID +//##################################################### +func GetHostUUID(nbmaster string, httpClient *http.Client, jwt string, host string) string { + fmt.Printf("\nGet the UUID of host %s...\n", host) + + uri := "https://" + nbmaster + ":" + port + "/netbackup/config/hosts"; + + request, _ := http.NewRequest(http.MethodGet, uri, nil) + query := request.URL.Query() + query.Add("filter", "hostName eq '" + host + "'") + request.URL.RawQuery = query.Encode() + + request.Header.Add("Authorization", jwt); + request.Header.Add("Accept", contentTypeV3); + + response, err := httpClient.Do(request) + + hostUuid := "" + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to get the host UUID") + } else { + if response.StatusCode == 200 { + data, _ := ioutil.ReadAll(response.Body) + var obj interface{} + json.Unmarshal(data, &obj) + response := obj.(map[string]interface{}) + hosts := response["hosts"].([]interface{}) + hostUuid = ((hosts[0].(map[string]interface{}))["uuid"]).(string) + fmt.Printf("Host UUID: %s\n", hostUuid); + } else { + printErrorResponse(response) + } + } + + return hostUuid +} + +//################################# +// Get exclude lists for this host +//################################# +func GetExcludeLists(nbmaster string, httpClient *http.Client, jwt string, hostUuid string) { + fmt.Printf("\nGet exclude list for host %s...\n", hostUuid) + + uri := "https://" + nbmaster + ":" + port + "/netbackup/config/hosts/" + hostUuid + "/configurations/exclude" + + request, _ := http.NewRequest(http.MethodGet, uri, nil) + request.Header.Add("Authorization", jwt); + request.Header.Add("Content-Type", contentTypeV3); + + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to get exclude list") + } else { + if response.StatusCode == 200 { + resp, _ := ioutil.ReadAll(response.Body) + var obj interface{} + json.Unmarshal(resp, &obj) + data := obj.(map[string]interface{}) + var excludeLists []interface{} = ((((data["data"].(map[string]interface{}))["attributes"]).(map[string]interface{}))["value"]).([]interface{}) + for _, list := range excludeLists { + fmt.Printf("%s\n", list) + } + } else { + printErrorResponse(response) + } + } +} + +//################################# +// Set exclude lists for this host +//################################# +func SetExcludeLists(nbmaster string, httpClient *http.Client, jwt string, hostUuid string) { + fmt.Printf("\nSet exclude list for host %s...\n", hostUuid) + + uri := "https://" + nbmaster + ":" + port + "/netbackup/config/hosts/" + hostUuid + "/configurations/exclude" + + excludeList := map[string]interface{}{ + "data": map[string]interface{}{ + "type": "hostConfiguration", + "attributes": map[string]interface{}{ + "name": "exclude", + "value": []string{"C:\\Program Files\\Veritas\\NetBackup\\bin\\*.lock", + "C:\\Program Files\\Veritas\\NetBackup\\bin\\bprd.d\\*.lock", + "C:\\Program Files\\Veritas\\NetBackup\\bin\\bpsched.d\\*.lock", + "C:\\Program Files\\Veritas\\Volmgr\\misc\\*", + "C:\\Program Files\\Veritas\\NetBackupDB\\data\\*", + "C:\\tmp"}}}} + + excludeListRequest, _ := json.Marshal(excludeList) + request, _ := http.NewRequest(http.MethodPut, uri, bytes.NewBuffer(excludeListRequest)) + request.Header.Add("Content-Type", contentTypeV3); + request.Header.Add("Authorization", jwt); + + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to set exclude list") + } else { + if response.StatusCode == 204 { + fmt.Printf("Exclude list was configured successfully.\n"); + } else { + if response.StatusCode == 404 { + uri := "https://" + nbmaster + ":" + port + "/netbackup/config/hosts/" + hostUuid + "/configurations" + request, _ := http.NewRequest(http.MethodPost, uri, bytes.NewBuffer(excludeListRequest)) + request.Header.Add("Content-Type", contentTypeV3); + request.Header.Add("Authorization", jwt); + + response, err := httpClient.Do(request) + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + } else { + if response.StatusCode == 204 { + fmt.Printf("Exclude list was configured successfully.\n"); + } else { + printErrorResponse(response) + } + } + } else { + printErrorResponse(response) + } + } + } +} + +//############################################# +// Get NetBackup processes running on this host +//############################################# +func GetProcesses(nbmaster string, httpClient *http.Client, jwt string, host string, hostUuid string, filter string) { + uri := "https://" + nbmaster + ":" + port + "/netbackup/admin/hosts/" + hostUuid + "/processes" + + request, _ := http.NewRequest(http.MethodGet, uri, nil) + request.Header.Add("Authorization", jwt); + request.Header.Add("Content-Type", contentTypeV3); + + if filter != "" { + query := request.URL.Query() + query.Add("filter", filter) + request.URL.RawQuery = query.Encode() + fmt.Printf("\nGet NetBackup processes with filter criteria %s running on %s...\n\n", filter, host) + } else { + fmt.Printf("\nGet NetBackup processes running on %s...\n\n", host) + } + + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to get processes.") + } else { + if response.StatusCode == 200 { + resp, _ := ioutil.ReadAll(response.Body) + var obj interface{} + json.Unmarshal(resp, &obj) + data := obj.(map[string]interface{}) + var processes []interface{} = data["data"].([]interface{}) + + fmt.Printf("pid processName priority memoryUsageMB startTime elapsedTime\n"); + fmt.Printf("=======.================.========.=============.======================.======================\n"); + for _, process := range processes { + attributes := ((process.(map[string]interface{}))["attributes"]).(map[string]interface{}) + + pid := attributes["pid"].(float64) + processName := attributes["processName"] + priority := attributes["priority"].(float64) + memoryUsageMB := attributes["memoryUsageMB"].(float64) + startTime := attributes["startTime"] + elapsedTime := attributes["elapsedTime"] + + fmt.Printf("%7.0f %-16s %8.0f %13.2f %22s %22s\n", pid, processName, priority, memoryUsageMB, startTime, elapsedTime); + } + } else { + printErrorResponse(response) + } + } +} + +//############################################## +// Get NetBackup services available on this host +//############################################## +func GetServices(nbmaster string, httpClient *http.Client, jwt string, host string, hostUuid string) { + fmt.Printf("\nGet NetBackup services available on %s...\n\n", host) + + uri := "https://" + nbmaster + ":" + port + "/netbackup/admin/hosts/" + hostUuid + "/services" + + request, _ := http.NewRequest(http.MethodGet, uri, nil) + request.Header.Add("Authorization", jwt); + request.Header.Add("Content-Type", contentTypeV3); + + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to get services") + } else { + if response.StatusCode == 200 { + resp, _ := ioutil.ReadAll(response.Body) + var obj interface{} + json.Unmarshal(resp, &obj) + data := obj.(map[string]interface{}) + var services []interface{} = data["data"].([]interface{}) + + fmt.Printf("id status\n"); + fmt.Printf("============.=========\n"); + for _, service := range services { + id := (service.(map[string]interface{}))["id"] + status := (((service.(map[string]interface{}))["attributes"]).(map[string]interface{}))["status"] + + fmt.Printf("%-12s %s\n", id, status); + } + } else { + printErrorResponse(response) + } + } +} + +//##################################################### +// Get NetBackup service with the given id on this host +//##################################################### +func GetService(nbmaster string, httpClient *http.Client, jwt string, host string, hostUuid string, serviceName string) { + fmt.Printf("\nGet NetBackup service %s on %s...\n\n", serviceName, host) + + uri := "https://" + nbmaster + ":" + port + "/netbackup/admin/hosts/" + hostUuid + "/services/" + serviceName + + request, _ := http.NewRequest(http.MethodGet, uri, nil) + request.Header.Add("Authorization", jwt); + request.Header.Add("Content-Type", contentTypeV3); + + response, err := httpClient.Do(request) + + if err != nil { + fmt.Printf("The HTTP request failed with error: %s\n", err) + panic("Unable to get services") + } else { + if response.StatusCode == 200 { + resp, _ := ioutil.ReadAll(response.Body) + var obj interface{} + json.Unmarshal(resp, &obj) + service := obj.(map[string]interface{})["data"].(map[string]interface{}) + + fmt.Printf("id status\n"); + fmt.Printf("============.=========\n"); + id := (service)["id"] + status := ((service)["attributes"]).(map[string]interface{})["status"] + + fmt.Printf("%-12s %s\n", id, status); + } else { + printErrorResponse(response) + } + } +} + +func printErrorResponse(response *http.Response) { + responseBody, _ := ioutil.ReadAll(response.Body) + var obj interface{} + json.Unmarshal(responseBody, &obj) + + if obj != nil { + error := obj.(map[string]interface{}) + errorCode := error["errorCode"].(float64) + errorMessage := error["errorMessage"].(string) + fmt.Printf("Error code:%.0f\nError message:%s\n", errorCode, errorMessage) + } else { + responseDetails, _ := httputil.DumpResponse(response, true); + fmt.Printf(string(responseDetails)) + } + + panic("Request failed"); +} diff --git a/recipes/go/utils/image_api_helper.go b/recipes/go/utils/image_api_helper.go new file mode 100644 index 0000000..98ff237 --- /dev/null +++ b/recipes/go/utils/image_api_helper.go @@ -0,0 +1,187 @@ +package images + +import ( + "fmt" + "strings" + "net/http" + "io/ioutil" +) + + +//################### +// Global Variables +//################### +const ( + protocol = "https://" + port = ":1556" + imagesUri = "/netbackup/catalog/images" + apiname = "/update-expiration-date" + update_apiname = "/update-primary-copy" + contentType = "application/vnd.netbackup+json;version=3.0" +) +func UpdateImageExpirationDateByBackupId(httpClient *http.Client, nbmaster string, token string, backupId string) { + fmt.Printf("\n Calling expire image by using backupId...\n") + uri := protocol + nbmaster + port + imagesUri + apiname + + jsonConfig := []byte(`{ + "data": { + "type": "byBackupId", + "attributes": { + "backupId": "$BACKUPID", + "date": "2020-02-01T20:36:28.750Z" + } + } + }`) + jsonString := string(jsonConfig) + requestJson := strings.Replace(jsonString, "$BACKUPID", backupId, 1) + + fmt.Println(requestJson) + + payload := strings.NewReader(string(requestJson)) + + request, _ := http.NewRequest(http.MethodPost, uri, payload) + + request.Header.Add("Authorization", token) + request.Header.Add("Content-Type", contentType) + request.Header.Add("cache-control", "no-cache") + + res, responseError := httpClient.Do(request) + + if ( res != nil ){ + defer res.Body.Close() + body, _ := ioutil.ReadAll(res.Body) + + fmt.Println(res) + fmt.Println(string(body)) + } else { + if ( responseError != nil ) { + fmt.Println(responseError.Error()) + } + fmt.Println("There is no response!") + } +} + +func UpdateImageExpirationDateByRecalculating(httpClient *http.Client, nbmaster string, token string, backupId string) { + fmt.Printf("\n Calling expire image by using recalculating and using additional params ( backupId )...\n") + uri := protocol + nbmaster + port + imagesUri + apiname + + jsonConfig := []byte(`{ + "data": { + "type": "byRecalculating", + "attributes": { + "backupId": "$BACKUPID", + "byBackupTime": true + } + } + }`) + jsonString := string(jsonConfig) + requestJson := strings.Replace(jsonString, "$BACKUPID", backupId, 1) + + fmt.Println(requestJson) + + payload := strings.NewReader(string(requestJson)) + + request, _ := http.NewRequest(http.MethodPost, uri, payload) + + request.Header.Add("Authorization", token) + request.Header.Add("Content-Type", contentType) + request.Header.Add("cache-control", "no-cache") + + res, responseError := httpClient.Do(request) + + if ( res != nil ){ + defer res.Body.Close() + body, _ := ioutil.ReadAll(res.Body) + + fmt.Println(res) + fmt.Println(string(body)) + } else { + if ( responseError != nil ) { + fmt.Println(responseError.Error()) + } + fmt.Println("There is no response!") + } +} + +func UpdateImageExpirationDateByServerName(httpClient *http.Client, nbmaster string, token string, servername string) { + fmt.Printf("\n Calling expire image by server name...\n") + uri := protocol + nbmaster + port + imagesUri + apiname + fmt.Println(uri) + jsonConfig := []byte(`{ + "data": { + "type": "byServerName", + "attributes": { + "serverName": "$SERVERNAME", + "date": "2025-02-01T20:36:28.750Z" + } + } + }`) + jsonString := string(jsonConfig) + requestJson := strings.Replace(jsonString, "$SERVERNAME", servername, 1) + + fmt.Println(requestJson) + + payload := strings.NewReader(string(requestJson)) + + request, _ := http.NewRequest(http.MethodPost, uri, payload) + + request.Header.Add("Authorization", token) + request.Header.Add("Content-Type", contentType) + request.Header.Add("cache-control", "no-cache") + + res, responseError := httpClient.Do(request) + + if ( res != nil ){ + defer res.Body.Close() + body, _ := ioutil.ReadAll(res.Body) + + fmt.Println(res) + fmt.Println(string(body)) + } else { + if ( responseError != nil ) { + fmt.Println(responseError.Error()) + } + fmt.Println("There is no response!") + } +} + +func UpdateImageExpirationDateByServerType(httpClient *http.Client, nbmaster string, token string, servertype string) { + fmt.Printf("\n Calling expire image by server type...\n") + uri := protocol + nbmaster + port + imagesUri + apiname + jsonConfig := []byte(`{ + "data": { + "type": "byServerType", + "attributes": { + "serverType": "$SERVERTYPE", + "date": "2020-02-01T20:36:28.750Z" + } + } + }`) + jsonString := string(jsonConfig) + requestJson := strings.Replace(jsonString, "$SERVERTYPE", servertype, 1) + + fmt.Println(requestJson) + + payload := strings.NewReader(string(requestJson)) + + request, _ := http.NewRequest(http.MethodPost, uri, payload) + + request.Header.Add("Authorization", token) + request.Header.Add("Content-Type", contentType) + request.Header.Add("cache-control", "no-cache") + + res, responseError := httpClient.Do(request) + + if ( res != nil ){ + defer res.Body.Close() + body, _ := ioutil.ReadAll(res.Body) + + fmt.Println(res) + fmt.Println(string(body)) + } else { + if ( responseError != nil ) { + fmt.Println(responseError.Error()) + } + fmt.Println("There is no response!") + } +} diff --git a/recipes/go/utils/image_api_update_pc.go b/recipes/go/utils/image_api_update_pc.go new file mode 100644 index 0000000..1aab6ed --- /dev/null +++ b/recipes/go/utils/image_api_update_pc.go @@ -0,0 +1,53 @@ +package images + +import ( + "fmt" + "strings" + "net/http" + "io/ioutil" +) + + +func UpdateImagePrimaryCopy(httpClient *http.Client, nbmaster string, token string, optionval string) { + uri := protocol + nbmaster + port + imagesUri + update_apiname + fmt.Printf("\n Calling UpdateImagePrimaryCopy\n USING : %s \n", uri ) + jsonConfig := []byte(`{ + "data": { + "type": "updatePrimaryCopyAttributes", + "attributes": { + "option": "copy", + "optionValue": "$OPTION_VALUE", + "startDate": "2019-01-26T15:39:00.729Z", + "endDate": "2019-03-26T15:39:00.729Z", + "policyName":"MyPolicy1" + } + } + }`) + jsonString := string(jsonConfig) + requestJson := strings.Replace(jsonString, "$OPTION_VALUE", optionval, 1) + + fmt.Println(requestJson) + + payload := strings.NewReader(string(requestJson)) + + request, _ := http.NewRequest(http.MethodPost, uri, payload) + + request.Header.Add("Authorization", token) + request.Header.Add("Content-Type", contentType) + request.Header.Add("cache-control", "no-cache") + + res, responseError := httpClient.Do(request) + + if ( res != nil ){ + defer res.Body.Close() + body, _ := ioutil.ReadAll(res.Body) + + fmt.Println(res) + fmt.Println(string(body)) + } else { + if ( responseError != nil ) { + fmt.Println(responseError.Error()) + } + fmt.Println("There is no response!") + } +} diff --git a/recipes/perl/access-control/README.md b/recipes/perl/access-control/README.md new file mode 100644 index 0000000..a7151ca --- /dev/null +++ b/recipes/perl/access-control/README.md @@ -0,0 +1,39 @@ +# NetBackup API Code Examples for Perl + +This directory contains scripts and code samples to aid in the migration of NetBackup 8.1.2 + roles to the new 8.3 design as well as scripts that can be used to generate typical roles using the new RBAC design. + +## Disclaimer + +These scripts are only meant to be used as reference. They are not intended to be used in production environment. + +## Prerequisites + +- NetBackup 8.3 or higher +- Perl 5.20.2 or higher + +## Executing the recipes in Perl + +**Examples of updating access control roles used by API Keys.** +Use the following commands to get RBAC principals behind registered API keys, get existing 0roles for RBAC gen1 roles +, and create new access control roles accordingly. + +- `perl list_api_keys.pl -hostname -username -password [-domain_name ] [-domain_type ]` +- `perl list_gen1_roles.pl -hostname -username -password [-domain_name ] [-domain_type ]` +- `perl create_access_control_role.pl -hostname -username -password -role_name [-role_description ] [-domain_name ] [-domain_type ]` + +**Examples creating roles based on role templates.** + +- `rbac_role_templates.pl --host nbumaster.domain.com --user dennis --pass secret --domain_type unixpwd --list_templates` +- `rbac_role_templates.pl --host nbumaster.domain.com --user bill --pass secret --domain_type NT --domain_name DOMAIN + --create_templates` +- `rbac_role_templates.pl --host nbumaster.domain.com --token Iojwei38djasdf893n-23ds --template "VMware Administrator"` +- `rbac_role_templates.pl --host nbumaster.domain.com --token Iojwei38djasdf893n-23ds --template "RHV Administrator +" --name "EU RHV Administrator"` + +**Examples migrating NetBackup 8.1.2 roles to new 8.3 administrator roles.** +- `rbac_user_migration.pl --host nbumaster.domain.com --user dennis --pass secret --domain_type unixpwd` +- `rbac_user_migration.pl --host nbumaster.domain.com --user bill --pass secret --domain_type NT --domain_name DOMAIN` +- `rbac_user_migration.pl --host nbumaster.domain.com --token Iojwei38djasdf893n-23ds` + + diff --git a/recipes/perl/access-control/access_control_api_requests.pl b/recipes/perl/access-control/access_control_api_requests.pl new file mode 100644 index 0000000..f40e702 --- /dev/null +++ b/recipes/perl/access-control/access_control_api_requests.pl @@ -0,0 +1,97 @@ +#!/usr/bin/env perl + +use LWP::UserAgent; +use JSON; + +my $content_type = "application/vnd.netbackup+json; version=4.0"; + +# Initialize HTTP client +my $http = LWP::UserAgent->new( + ssl_opts => { verify_hostname => 0, verify_peer => 0 }, + protocols_allowed => ['https'] +); + +# List api keys +sub list_api_keys { + my ($base_url, $token) = @_; + + my $media_type = "application/vnd.netbackup+json;version=4"; + my $api_keys_url = "$base_url/security/api-keys"; + + # Update http client with default header + $http->default_header('Accept' => $media_type); + $http->default_header('Authorization' => $token); + + my $response = $http->get($api_keys_url); + + unless ($response->is_success) { + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + + die "Failed to get api keys.\n"; + } + + my $response_content = decode_json($response->content); + print "API Keys: ", $response_content, "\n"; +} + +# List rbac roles +sub list_gen1_roles { + my ($base_url, $token) = @_; + + my $media_type = "application/vnd.netbackup+json;version=1"; + my $gen1_roles_url = "$base_url/rbac/roles"; + + $http->default_header('Accept' => $media_type); + $http->default_header('Authorization' => $token); + + my $response = $http->get($gen1_roles_url); + + unless ($response->is_success) { + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + + die "Failed to get Gen-1 roles.\n"; + } + + my $response_content = decode_json($response->content); + print "Gen-1 roles: ", $response_content, "\n"; +} + +# Create access control role +sub create_access_control_role { + my ($base_url, $token, $name, $desc) = @_; + + my $media_type = "application/vnd.netbackup+json;version=4"; + my $access_control_roles_url = "$base_url/access-control/roles"; + + $http->default_header('Accept' => $media_type); + $http->default_header('Authorization' => $token); + + my %role = ( + 'data' => { + 'type' => 'accessControlRole', + 'attribute' => { + 'name' => $name, + 'description' => $desc + } + } + ); + + my $role_body = encode_json(\%role); + + my $response = $http->post($access_control_role_url, 'Content-Type' => $media_type, Content => $role_body); + + unless ($response->is_success) { + print "HTTP POST error code: ", $response->code, "\n"; + print "HTTP POST error message: ", $response->message, "\n"; + + die "Failed to create $name role.\n"; + } + + my $response_content = decode_json($response->content); + my $new_role_id = $response_content->{data}{id}; + print "$name role created with ID $new_role_id\n"; +} + +1; diff --git a/recipes/perl/access-control/create_access_control_role.pl b/recipes/perl/access-control/create_access_control_role.pl new file mode 100644 index 0000000..34132c3 --- /dev/null +++ b/recipes/perl/access-control/create_access_control_role.pl @@ -0,0 +1,47 @@ +#!/usr/bin/env perl + +use Getopt::Long; + +require 'api_requests.pl'; +require 'access_control_api_requests.pl'; + +my $hostname; +my $username; +my $password; +my $domain_name; +my $domain_type; +my $role_name; +my $role_description; + +my $base_url; +my $token; + +GetOptions( + 'hostname=s' => \$hostname, + 'username=s' => \$username, + 'password=s' => \$password, + 'domain_name=s' => \$domain_name, + 'domain_type=s' => \$domain_type, + 'role_name=s' => \$role_name, + 'role_description=s' => \$role_description +) or pod2usage(2); + +$hostname ne "" or die "Please provide a value for '--hostname'\n"; + +$username ne "" or die "Please provide a value for '--username'\n"; + +$password ne "" or die "Please provide a value for '--password'\n"; + +$role_name ne "" or die "Please provide a value for '--role_name'\n"; + +$base_url = "https://$hostname/netbackup"; +$token = perform_login($base_url, $username, $password, $domain_name, $domain_type); + +create_access_control_role($base_url, $token, $role_name, $role_description); + + +sub print_usage { + say "Usage:"; + say "perl create_access_control_role.pl -hostname -username -password -role_name [-role_description ] [-domain_name ] [-domain_type ]"; +} + diff --git a/recipes/perl/access-control/list_api_keys.pl b/recipes/perl/access-control/list_api_keys.pl new file mode 100644 index 0000000..aae4365 --- /dev/null +++ b/recipes/perl/access-control/list_api_keys.pl @@ -0,0 +1,41 @@ +#!/usr/bin/env perl + +use Getopt::Long; + +require 'api_requests.pl'; +require 'access_control_api_requests.pl'; + +my $hostname; +my $username; +my $password; +my $domain_name; +my $domain_type; + +my $base_url; +my $token; + +GetOptions( + 'hostname=s' => \$hostname, + 'username=s' => \$username, + 'password=s' => \$password, + 'domain_name=s' => \$domain_name, + 'domain_type=s' => \$domain_type +) or pod2usage(2); + +$hostname ne "" or die "Please provide a value for '--hostname'\n"; + +$username ne "" or die "Please provide a value for '--username'\n"; + +$password ne "" or die "Please provide a value for '--password'\n"; + +$base_url = "https://$hostname/netbackup"; +$token = perform_login($base_url, $username, $password, $domain_name, $domain_type); + +list_api_keys($base_url, $token); + + +sub print_usage { + say "Usage:"; + say "perl list_api_keys.pl -hostname -username -password [-domain_name ] [-domain_type ]"; +} + diff --git a/recipes/perl/access-control/list_gen1_roles.pl b/recipes/perl/access-control/list_gen1_roles.pl new file mode 100644 index 0000000..7d56058 --- /dev/null +++ b/recipes/perl/access-control/list_gen1_roles.pl @@ -0,0 +1,41 @@ +#!/usr/bin/env perl + +use Getopt::Long; + +require 'api_requests.pl'; +require 'access_control_api_requests.pl'; + +my $hostname; +my $username; +my $password; +my $domain_name; +my $domain_type; + +my $base_url; +my $token; + +GetOptions( + 'hostname=s' => \$hostname, + 'username=s' => \$username, + 'password=s' => \$password, + 'domain_name=s' => \$domain_name, + 'domain_type=s' => \$domain_type +) or pod2usage(2); + +$hostname ne "" or die "Please provide a value for '--hostname'\n"; + +$username ne "" or die "Please provide a value for '--username'\n"; + +$password ne "" or die "Please provide a value for '--password'\n"; + +$base_url = "https://$hostname/netbackup"; +$token = perform_login($base_url, $username, $password, $domain_name, $domain_type); + +list_gen1_roles($base_url, $token); + + +sub print_usage { + say "Usage:"; + say "perl list_gen1_roles.pl -hostname -username -password [-domain_name ] [-domain_type ]"; +} + diff --git a/recipes/perl/access-control/rbac_role_templates.pl b/recipes/perl/access-control/rbac_role_templates.pl new file mode 100644 index 0000000..12bc0f1 --- /dev/null +++ b/recipes/perl/access-control/rbac_role_templates.pl @@ -0,0 +1,793 @@ +#!/usr/bin/env perl +# $Copyright: Copyright (c) 2020 Veritas Technologies LLC. All rights reserved $ + +use strict; +use warnings; +use Data::Dumper; +use Getopt::Long; +use JSON::PP; +use LWP::Protocol::https; +use LWP::UserAgent; +use Net::SSL; +use Pod::Usage; +use Term::ReadKey; + + +# Set umask to 022 to make sure files and directories +# are not created with world writable permissions. +if ($^O !~ m/Win/i) { + umask 0022; +} + +# Configuration variables +my $hostname = 'localhost'; +my $username = ''; +my $password = ''; +my $domain_type = ''; +my $domain_name = ''; +my $token = ''; +my $list_templates = 0; +my $create_all = 0; +my $template = ''; +my $name = ''; +my $description = ''; +my %vmware_role_operation_map = ( + '|ASSETS|VMWARE|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|ASSETS|VMWARE|PROTECT|', + '|OPERATIONS|ASSETS|VMWARE|RESTORE_DESTINATION|', + '|OPERATIONS|ASSETS|VMWARE|VM|RECOVER|', + '|OPERATIONS|ASSETS|VMWARE|VM|GRANULAR_RESTORE|', + '|OPERATIONS|ASSETS|VMWARE|VM|INSTANT_ACCESS_RECOVER|', + '|OPERATIONS|ASSETS|VMWARE|VM|INSTANT_ACCESS_FILES_DOWNLOAD|', + '|OPERATIONS|ASSETS|VMWARE|VM|INSTANT_ACCESS_FILES_RESTORE|', + '|OPERATIONS|ASSETS|VMWARE|VM|RESTORE_OVERWRITE|', + '|OPERATIONS|ASSETS|VMWARE|VM|CLOUD_RECOVER|', + ], + '|MANAGE|ACCESSHOSTS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|' + ], + '|MANAGE|HOSTS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|UPDATE|' + ], + '|MANAGE|HOSTS|HOST-PROPERTIES|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|' + ], + '|MANAGE|IMAGES|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|MANAGE|IMAGES|VIEW-CONTENTS|' + ], + '|MANAGE|JOBS|' => [ + '|OPERATIONS|VIEW|' + ], + '|MANAGE|RESOURCELIMITS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|' + ], + '|MANAGE|SERVERS|TRUSTED-MASTER-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ], + '|PROTECTION|PROTECTION_PLAN|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|SUBSCRIBE|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_POLICY_ATTRIBUTES|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_SCHEDULE_FULL_INCR_ATTRIBUTES|' + ], + '|SECURITY|ACCESS-CONTROL|ROLES|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|SECURITY|ACCESS-CONTROL|ROLES|ASSIGN-ACCESS|' + ], + '|STORAGE|STORAGE-UNITS|' => [ + '|OPERATIONS|VIEW|' + ], + '|STORAGE|TARGET-STORAGE-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ] +); +my %vrp_role_operation_map = ( + '|MANAGE|RESILIENCY|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|' + ] +); +my %rhv_role_operation_map = ( + '|ASSETS|RHV|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|ASSETS|RHV|PROTECT|', + '|OPERATIONS|ASSETS|RHV|RESTORE_DESTINATION|', + '|OPERATIONS|ASSETS|RHV|VM|RECOVER|', + '|OPERATIONS|ASSETS|RHV|VM|RESTORE_OVERWRITE|' + ], + '|MANAGE|ACCESSHOSTS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|' + ], + '|MANAGE|HOSTS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|UPDATE|' + ], + '|MANAGE|JOBS|' => [ + '|OPERATIONS|VIEW|' + ], + '|MANAGE|RESOURCELIMITS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|' + ], + '|MANAGE|SERVERS|TRUSTED-MASTER-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ], + '|PROTECTION|PROTECTION_PLAN|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|SUBSCRIBE|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_POLICY_ATTRIBUTES|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_SCHEDULE_FULL_INCR_ATTRIBUTES|' + ], + '|SECURITY|ACCESS-CONTROL|ROLES|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|SECURITY|ACCESS-CONTROL|ROLES|ASSIGN-ACCESS|' + ], + '|STORAGE|STORAGE-UNITS|' => [ + '|OPERATIONS|VIEW|' + ], + '|STORAGE|TARGET-STORAGE-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ] +); +my %cloud_role_operation_map = ( + '|ASSETS|CLOUD|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|ASSETS|CLOUD|UPDATE_CONFIGURATION|', + '|OPERATIONS|ASSETS|CLOUD|PROTECT|', + '|OPERATIONS|ASSETS|CLOUD|RESTORE_DESTINATION|', + '|OPERATIONS|ASSETS|CLOUD|RESTORE_ALTERNATE|', + '|OPERATIONS|ASSETS|CLOUD|RESTORE_ORIGINAL|', + '|OPERATIONS|ASSETS|CLOUD|RESTORE_OVERWRITE|', + '|OPERATIONS|ASSETS|CLOUD|GRANULAR_RESTORE|' + ], + '|MANAGE|IMAGES|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|MANAGE|IMAGES|VIEW-CONTENTS|' + ], + '|MANAGE|JOBS|' => [ + '|OPERATIONS|VIEW|' + ], + '|MANAGE|SERVERS|TRUSTED-MASTER-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ], + '|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|MANAGE-ACCESS|' + ], + '|MANAGE|SNAPSHOT-MGMT-SERVER|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|MANAGE|SNAPSHOT-MGMT-SERVER|DISCOVER|', + '|OPERATIONS|MANAGE|SNAPSHOT-MGMT-SERVER|UPDATE_ASSOCIATE_MEDIA_SERVERS|', + '|OPERATIONS|MANAGE|SNAPSHOT-MGMT-SERVER|VIEW_ASSOCIATE_MEDIA_SERVERS|', + '|OPERATIONS|MANAGE-ACCESS|' + ], + '|PROTECTION|PROTECTION_PLAN|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|SUBSCRIBE|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_POLICY_ATTRIBUTES|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_SCHEDULE_FULL_INCR_ATTRIBUTES|' + ], + '|SECURITY|ACCESS-CONTROL|ROLES|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|SECURITY|ACCESS-CONTROL|ROLES|ASSIGN-ACCESS|' + ], + '|STORAGE|STORAGE-UNITS|' => [ + '|OPERATIONS|VIEW|' + ], + '|STORAGE|TARGET-STORAGE-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ] +); +my %mssql_role_operation_map = ( + '|ASSETS|MSSQL|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|MSSQL|PROTECT|', + '|OPERATIONS|MSSQL|RECOVER|', + '|OPERATIONS|MSSQL|ALT_RECOVER|', + '|OPERATIONS|MSSQL|OVERWRITE_RECOVER|', + '|OPERATIONS|MSSQL|INSTANT_ACCESS_RECOVER|', + '|OPERATIONS|MSSQL|DATABASE|DISCOVER|', + '|OPERATIONS|MSSQL|AVAILABILITY_GROUP|DISCOVER|', + '|OPERATIONS|MSSQL|INSTANCE|VALIDATE_CREDENTIAL|' + ], + '|CREDENTIALS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|MANAGE|CREDENTIALS|ASSIGNABLE|' + ], + '|MANAGE|JOBS|' => [ + '|OPERATIONS|VIEW|' + ], + '|MANAGE|SERVERS|TRUSTED-MASTER-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ], + '|PROTECTION|PROTECTION_PLAN|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|SUBSCRIBE|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_POLICY_ATTRIBUTES|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_SCHEDULE_FULL_INCR_ATTRIBUTES|', + '|OPERATIONS|PROTECTION|PROTECTION_PLAN|DELEGATE_SCHEDULE_TLOG_ATTRIBUTES|' + ], + '|SECURITY|ACCESS-CONTROL|ROLES|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|SECURITY|ACCESS-CONTROL|ROLES|ASSIGN-ACCESS|' + ], + '|STORAGE|STORAGE-UNITS|' => [ + '|OPERATIONS|VIEW|' + ], + '|STORAGE|TARGET-STORAGE-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ] +); +my %storage_role_operation_map = ( + '|MANAGE|MEDIA-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ], + '|MANAGE|REMOTE-MASTER-SERVER-CA-CERTIFICATES|' => [ + '|OPERATIONS|VIEW|' + ], + '|MANAGE|SERVERS|TRUSTED-MASTER-SERVERS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|TOKENS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|VIEW|' + ], + '|SECURITY|KMS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|SECURITY|KMS|SERVICES|VIEW|' + ], + '|STORAGE|CLOUD|' => [ + '|OPERATIONS|VIEW|' + ], + '|STORAGE|DISK-POOLS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|VIEW|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|' + ], + '|STORAGE|STORAGE-SERVERS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|' + ], + '|STORAGE|STORAGE-SERVERS|DISK-VOLUMES|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|' + ], + '|STORAGE|STORAGE-UNITS|' => [ + '|OPERATIONS|VIEW|', + '|OPERATIONS|ADD|', + '|OPERATIONS|UPDATE|', + '|OPERATIONS|DELETE|' + ], + '|STORAGE|TARGET-STORAGE-SERVERS|' => [ + '|OPERATIONS|VIEW|' + ] +); +my %security_role_operation_map = ( + '|' => [ + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|VIEW|' + ], + '|MANAGE|HOSTS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|MANAGE|HOSTS|COMMENT|', + '|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|DELETE|', + '|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|UPDATE|', + '|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|VIEW|', + '|OPERATIONS|MANAGE|HOSTS|RESET|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|ACCESS-CONTROL|PRINCIPALS|' => [ + '|OPERATIONS|SECURITY|ACCESS-CONTROL|PRINCIPALS|ASSIGN-TO-ROLE|' + ], + '|SECURITY|ACCESS-CONTROL|ROLES|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|SECURITY|ACCESS-CONTROL|ROLES|ASSIGN-ACCESS|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|CERTIFICATE-AUTHORITIES|' => [ + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|CERTIFICATE-AUTHORITIES|MIGRATE-CA|', + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|CERTIFICATE-AUTHORITIES|VIEW-HOSTS-MIGRATE-CA|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|ECA|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|ECA|RESET|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|' => [ + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|REVOKE|', + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|DISSOCIATE|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|TOKENS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|' + ], + '|SECURITY|CREDENTIALS|' => [ + '|OPERATIONS|ADD|' + ], + '|SECURITY|IDP|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|KMS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|SECURITY|KMS|SERVICES|CREATE|', + '|OPERATIONS|SECURITY|KMS|SERVICES|VIEW|', + '|OPERATIONS|SECURITY|KMS|VALIDATE|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|SETTINGS|' => [ + '|OPERATIONS|SECURITY|SETTINGS|RELOAD|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|USERS|API-KEYS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|USERS|CERTIFICATE-MANAGEMENT|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|' + ], + '|SECURITY|USERS|USER-SESSIONS|' => [ + '|OPERATIONS|DELETE|', + '|OPERATIONS|SECURITY|USERS|USER-SESSIONS|CLOSE|', + '|OPERATIONS|SECURITY|USERS|USER-SESSIONS|CLOSE-ALL|', + '|OPERATIONS|SECURITY|USERS|USER-SESSIONS|UNLOCK|', + '|OPERATIONS|SECURITY|USERS|USER-SESSIONS|VIEW-LOCKED-USERS|', + '|OPERATIONS|UPDATE|' + ] +); +my %role_template_data = ( + 'VMware Administrator' => { + 'name' => 'VMware Administrator', + 'description' => 'Provides all the permissions necessary to manage protection for VMware VMs through Protection Plans.', + 'template' => \%vmware_role_operation_map, + }, + 'VRP Administrator' => { + 'name' => 'VRP Administrator', + 'description' => 'Provides all the permissions necessary to manage Resiliency Platform for VMware assets.', + 'template' => \%vrp_role_operation_map, + }, + 'RHV Administrator' => { + 'name' => 'RHV Administrator', + 'description' => 'Provides all the permissions necessary to manage protection for RedHat Virtualization VMs through Protection Plans.', + 'template' => \%rhv_role_operation_map, + }, + 'Cloud Administrator' => { + 'name' => 'Cloud Administrator', + 'description' => 'Provides all the permissions necessary to manage protection of cloud assets using Protection Plans.', + 'template' => \%cloud_role_operation_map, + }, + 'MS-SQL Administrator' => { + 'name' => 'MS-SQL Administrator', + 'description' => 'Provides all the permissions necessary to manage protection for Microsoft SQL Server databases using Protection Plans.', + 'template' => \%mssql_role_operation_map, + }, + 'Storage Administrator' => { + 'name' => 'Storage Administrator', + 'description' => 'Provides all the permissions necessary to configure and manage disk-based storage and cloud storage for NetBackup.', + 'template' => \%storage_role_operation_map, + }, + 'Security Administrator' => { + 'name' => 'Security Administrator', + 'description' => 'Security administrator with privileges for performing actions including access control, certificates, security settings etc.', + 'template' => \%security_role_operation_map, +} +); + +# Parse command line options +my ($help, $man, $debug); +GetOptions( + 'help|h!' => \$help, + 'man|m!' => \$man, + 'debug|d!', => \$debug, + 'list_templates' => \$list_templates, + 'hostname|host=s' => \$hostname, + 'username|user=s' => \$username, + 'password|pass=s' => \$password, + 'domain_type=s' => \$domain_type, + 'domain_name=s' => \$domain_name, + 'token=s' => \$token, + 'create_templates' => \$create_all, + 'template=s' => \$template, + 'name=s' => \$name, + 'description=s' => \$description +) or pod2usage(2); + +if ($help) { + pod2usage(1); + exit; +} + +if ($man) { + pod2usage(-verbose => 2); + exit; +} + +if ($list_templates) { + print_templates(); + exit; +} + +unless ($create_all or $template) { + pod2usage(1); + exit 1; +} + +if ($create_all and $template) { + print "Cannot specify both --create_templates and --template for role creation.\n"; + pod2usage(1); + exit 1; +} + +if ($create_all and ($name or $description)) { + print "--name and --description are only valid with the --template option.\n"; + pod2usage(1); + exit 1; +} + +if ($template) { + my $found = 0; + foreach my $role (keys %role_template_data) { + if ($template =~ /$role/) { + $found = 1; + } + } + + unless ($found) { + print "Invalid --template specified [$template]\n"; + print "Valid templates are:\n"; + print_templates(); + exit 1; + } +} + +if ($name) { + $role_template_data{$template}{name} = $name; + print "Role name provided: " . $role_template_data{$template}{name} . "\n"; +} + +if ($description) { + $role_template_data{$template}{description} = $description; + print "Role description provided: " . $role_template_data{$template}{description} . "\n"; +} + +# Initialize HTTP client +my $http = LWP::UserAgent->new( + ssl_opts => {verify_hostname => 0, verify_peer => 0}, + protocols_allowed => ['https'] +); +my $response; + +# Ping server to verify connection and get API version +my $ping_url = "https://$hostname/netbackup/ping"; +$response = $http->get($ping_url, 'Accept' => 'text/plain'); +unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to ping server!\n" ; +} + +my $api_version = $response->header('x-netbackup-api-version'); +if ($api_version < 4) { # NetBackup 8.3 + die "Script should not be run on NetBackup releases before 8.3!\n"; +} + +# Set media type with discovered API version +my $media_type = "application/vnd.netbackup+json;version=$api_version"; + +# Log in to get a token if needed +unless ($token) { + + unless ($password) { + ReadMode('noecho'); + print "Password:"; + $password = ReadLine(0); + chomp($password); + } + my $login_url = "https://$hostname/netbackup/login"; + my %creds = ( + domainType => "$domain_type", + domainName => "$domain_name", + userName => "$username", + password => "$password" + ); + my $login_body = encode_json(\%creds); + $response = $http->post($login_url, 'Content-Type' => $media_type, Content => $login_body); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to log into server!\n" ; + } + $token = decode_json($response->content)->{token}; +} + +# Update HTTP client with default headers +$http->default_header('Accept' => $media_type); +$http->default_header('Authorization' => $token); + +foreach my $role (keys %role_template_data) { + if ($create_all or $template =~ /$role/) { + print "Creating role from template: $role\n"; + + my $access_control_roles_url = "https://$hostname/netbackup/access-control/roles"; + my %role_admin = ( + 'data' => { + 'type' => 'accessControlRole', + 'attributes' => { + 'name' => $role_template_data{$role}{name}, + 'description' => $role_template_data{$role}{description} + } + } + ); + + my $role_admin_body = encode_json(\%role_admin); + + $response = $http->post($access_control_roles_url, 'Content-Type' => $media_type, Content => $role_admin_body); + + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + + if ($response->code() == 401) { + print "Access to perform the operation was denied.\n"; + } + + if ($response->code() == 409) { + print "Failed to create $role_template_data{$role}{name} role, it already exists!\n"; + next; + } + + die "Failed to create $role_template_data{$role}{name} role!\n" ; + } + my $response_content = decode_json($response->content); + my $new_role_id = $response_content->{data}{id}; + print "$role_template_data{$role}{name} role created with ID: ", $new_role_id, "\n"; + + # Create access-definitions for new role + for my $managed_object (keys %{$role_template_data{$role}{template}}) { + my $access_definitions_url = "https://$hostname/netbackup/access-control/managed-objects/$managed_object/access-definitions"; + my $operations = $role_template_data{$role}{template}{$managed_object}; + my $access_definition_object = encode_json(generate_access_definition_object($new_role_id, $managed_object, $operations)); + $response = $http->post($access_definitions_url, 'Content-Type' => $media_type, Content => $access_definition_object); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to create access definition for $role_template_data{$role}{name} role!\n"; + } + } + } +} + +sub print_templates { + foreach my $role (keys %role_template_data) { + print $role_template_data{$role}->{name} . "\n"; + } +} + +sub generate_access_control_operation_resource_identifier_objects { + my (@operations) = @_; + my @data; + foreach my $operation (@operations) { + my %identifier = (type => 'accessControlOperation', id => $operation); + push @data, \%identifier; + } + my %objects = (data => \@data); + return \%objects; +} + +sub generate_access_definition_object { + my ($role_id, $managed_object, $operations_ref) = @_; + my @operations = @{$operations_ref}; + my %object = ( + data => { + type => "accessDefinition", + attributes => { + propagation => "OBJECT_AND_CHILDREN" + }, + relationships => { + role => { + data => { + type => "accessControlRole", + id => "$role_id" + } + }, + operations => generate_access_control_operation_resource_identifier_objects(@operations), + managed_object => { + data => { + type => "managedObject", + id => "$managed_object" + } + } + } + } + ); + return \%object; +} + + +__END__ + +=head1 NAME + +rbac_role_templates.pl - create RBAC template roles + +=head1 SYNOPSIS + +B [--debug] [--hostname master_server] [--username user] [--password secret] [--domain_type type] [--domain_name name] [--token JWT] [--list_templates] [--create_templates] [--template template] [--name name] [--description description] [--help] [--man] + +=head1 DESCRIPTION + +B creates roles based on templates for the new RBAC framework. + +Access definitions are created for the new role using a suggested list of managed objects and operations. + +These templates can be modified/extended as needed. + +For more detailed information on RBAC please see the NetBackup Security & Encryption guide. + +To get the latest version of this script please check out the NetBackup API Code Samples repo on GitHub at L. + +=head1 DEPENDENCIES + +This script requires these other non-core modules: + +=over 4 + +=item LWP::Protocol::https + +=item LWP::UserAgent + +=item Net::SSL + +=back + +=head1 OPTIONS + +=over 4 + +=item B<-h, --help> + +Print a brief summary of the options to B and exit. + +=item B<-m, --man> + +Print the full manual page for B and exit. + +=item B<-d, --debug> + +Prints the full HTTP response object when an API call fails. Useful for debugging script execution problems. + +=item B<--host, --hostname> + +The hostname of the master server to run script against. This script can be run from any system as long as there is network connectivity to the master server specified. Defaults to 'localhost' if not specified. + +=item B<--user, --username> + +The API user to authenticate with on the master server. Required if token is not provided. + +=item B<--pass, --password> + +The password to authenticate with on the master server. Required if token is not provided. + +=item B<--domain_type> + +The domain type to authenticate with on the master server. + +=item B<--domain_name> + +The domain name to authenticate with on the master server. + +=item B<--token> + +The JWT or API key value to use instead of authenticating and creating a new user session. Required if username and password are not provided. + +=item B<--list_templates> + +List all the template roles. + +=item B<--create_templates> + +Creates all role templates. + +=item B<--template> + +The name of the template role to create. + +=item B<--name> + +The role name to overwrite the default value. + +=item B<--description> + +The role description to overwrite the default value. + +=back + +=head1 EXAMPLES + +rbac_role_templates.pl --host nbumaster.domain.com --user dennis --pass secret --domain_type unixpwd --list_templates + +rbac_role_templates.pl --host nbumaster.domain.com --user bill --pass secret --domain_type NT --domain_name DOMAIN --create_templates + +rbac_role_templates.pl --host nbumaster.domain.com --token Iojwei38djasdf893n-23ds --template "VMware Administrator" + +rbac_role_templates.pl --host nbumaster.domain.com --token Iojwei38djasdf893n-23ds --template "RHV Administrator" --name "EU RHV Administrator" + +=head1 LICENSE AND COPYRIGHT + +Copyright 2020 Veritas Technologies LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +=cut diff --git a/recipes/perl/access-control/rbac_user_migration.pl b/recipes/perl/access-control/rbac_user_migration.pl new file mode 100644 index 0000000..d60f3f5 --- /dev/null +++ b/recipes/perl/access-control/rbac_user_migration.pl @@ -0,0 +1,592 @@ +#!/usr/bin/env perl +# $Copyright: Copyright (c) 2020 Veritas Technologies LLC. All rights reserved $ + +use strict; +use warnings; +use Data::Dumper; +use Getopt::Long; +use JSON::PP; +use LWP::Protocol::https; +use LWP::UserAgent; +use Pod::Usage; + + +# Set umask to 022 to make sure files and directories +# are not created with world writable permissions. +if ($^O !~ m/Win/i) { + umask 0022; +} + +# Configuration variables +my $hostname = 'localhost'; +my $username = ''; +my $password = ''; +my $domain_type = ''; +my $domain_name = ''; +my $token = ''; +my %security_role_operation_map = ( + '|' => [ + '|OPERATIONS|MANAGE-ACCESS|', + '|OPERATIONS|VIEW|' + ], + '|MANAGE|HOSTS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|MANAGE|HOSTS|COMMENT|', + '|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|DELETE|', + '|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|UPDATE|', + '|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|VIEW|', + '|OPERATIONS|MANAGE|HOSTS|RESET|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|ACCESS-CONTROL|PRINCIPALS|' => [ + '|OPERATIONS|SECURITY|ACCESS-CONTROL|PRINCIPALS|ASSIGN-TO-ROLE|' + ], + '|SECURITY|ACCESS-CONTROL|ROLES|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|SECURITY|ACCESS-CONTROL|ROLES|ASSIGN-ACCESS|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|CERTIFICATE-AUTHORITIES|' => [ + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|CERTIFICATE-AUTHORITIES|MIGRATE-CA|', + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|CERTIFICATE-AUTHORITIES|VIEW-HOSTS-MIGRATE-CA|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|ECA|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|ECA|RESET|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|' => [ + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|REVOKE|', + '|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|DISSOCIATE|' + ], + '|SECURITY|CERTIFICATE-MANAGEMENT|TOKENS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|' + ], + '|SECURITY|CREDENTIALS|' => [ + '|OPERATIONS|ADD|' + ], + '|SECURITY|IDP|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|KMS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|SECURITY|KMS|SERVICES|CREATE|', + '|OPERATIONS|SECURITY|KMS|SERVICES|VIEW|', + '|OPERATIONS|SECURITY|KMS|VALIDATE|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|SETTINGS|' => [ + '|OPERATIONS|SECURITY|SETTINGS|RELOAD|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|USERS|API-KEYS|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|', + '|OPERATIONS|UPDATE|' + ], + '|SECURITY|USERS|CERTIFICATE-MANAGEMENT|' => [ + '|OPERATIONS|ADD|', + '|OPERATIONS|DELETE|' + ], + '|SECURITY|USERS|USER-SESSIONS|' => [ + '|OPERATIONS|DELETE|', + '|OPERATIONS|SECURITY|USERS|USER-SESSIONS|CLOSE|', + '|OPERATIONS|SECURITY|USERS|USER-SESSIONS|CLOSE-ALL|', + '|OPERATIONS|SECURITY|USERS|USER-SESSIONS|UNLOCK|', + '|OPERATIONS|SECURITY|USERS|USER-SESSIONS|VIEW-LOCKED-USERS|', + '|OPERATIONS|UPDATE|' + ] +); + +# Parse command line options +my ($help, $man, $debug); +GetOptions( + 'help|h!' => \$help, + 'man|m!' => \$man, + 'debug|d!', => \$debug, + 'hostname|host=s' => \$hostname, + 'username|user=s' => \$username, + 'password|pass=s' => \$password, + 'domain_type=s' => \$domain_type, + 'domain_name=s' => \$domain_name, + 'token=s' => \$token +) or pod2usage(2); + +if ($help) { + pod2usage(1); + exit; +} + +if ($man) { + pod2usage(-verbose => 2); + exit; +} + +if (!($token || ($username && $password))) { + print "Either -username and -password needs to be specified or -token needs to be specified\n"; + pod2usage(2); +} + +# Initialize HTTP client +my $http = LWP::UserAgent->new( + ssl_opts => {verify_hostname => 0, verify_peer => 0}, + protocols_allowed => ['https'] +); +my $response; + +# Ping server to verify connection and get API version +my $ping_url = "https://$hostname/netbackup/ping"; +$response = $http->get($ping_url, 'Accept' => 'text/plain'); +unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to ping server!\n" ; +} + +my $api_version = $response->header('x-netbackup-api-version'); +if ($api_version < 4) { # NetBackup 8.3 + die "Script should not be run on NetBackup releases before 8.3!\n"; +} + +# Set meda type with discovered API version +my $media_type = "application/vnd.netbackup+json;version=$api_version"; + +# Log in to get a token if needed +unless ($token) { ## REMOVE token ## + my $login_url = "https://$hostname/netbackup/login"; + my %creds = ( + domainType => "$domain_type", + domainName => "$domain_name", + userName => "$username", + password => "$password" + ); + my $login_body = encode_json(\%creds); + $response = $http->post($login_url, 'Content-Type' => $media_type, Content => $login_body); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to log into server!\n" ; + } + $token = decode_json($response->content)->{token}; +} + +# Update HTTP client with default headers +$http->default_header('Accept' => $media_type); +$http->default_header('Authorization' => $token); + +# Find old backup and security admin role IDs +my $rbac_roles_url = "https://$hostname/netbackup/rbac/roles"; +$response = $http->get($rbac_roles_url); +unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + if ($response->code() == 401) { + print "Access to perform the operation was denied.\n"; + } + die "Failed to get old RBAC roles!\n" ; +} +my ($old_backup_admin_role_id, $old_security_admin_role_id) = extract_role_ids($response); + +# Find user and group principals from old access rules that reference backup and security roles +my $rbac_access_rules_url = "https://$hostname/netbackup/rbac/access-rules"; +$response = $http->get($rbac_access_rules_url); +unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to get old RBAC access rules!\n" ; +} +my ($backup_user_principals_ref, $backup_group_principals_ref, $security_user_principals_ref, $security_group_principals_ref) = extract_principals($response); + +# Remove duplicates from security so that any user/group that exists in both will only be added to Administrator role +$security_user_principals_ref = remove_duplicates($backup_user_principals_ref, $security_user_principals_ref); +$security_group_principals_ref = remove_duplicates($backup_group_principals_ref, $security_group_principals_ref); + +# Dereference arrays for later use +my @backup_user_principals = @{$backup_user_principals_ref}; +my @backup_group_principals = @{$backup_group_principals_ref}; +my @security_user_principals = @{$security_user_principals_ref}; +my @security_group_principals = @{$security_group_principals_ref}; + +if (!@backup_user_principals and !@backup_group_principals and !@security_user_principals and !@security_group_principals) { + print "No principals found in old RBAC access rules!\n"; + exit; +} + +# Prompt user for backup to Administrator migration confirmation +if (@backup_user_principals) { + print "Found the following backup administrator principals:\n"; + foreach my $backup_user (@backup_user_principals) { + print "\t$backup_user\n"; + } +} +if (@backup_group_principals) { + print "Found the following backup administrator group principals:\n"; + foreach my $backup_group (@backup_group_principals) { + print "\t$backup_group\n"; + } +} +print "\nWould you like to migrate these principals to the Administrator role? (y/N) "; +my $do_backup = <>; +chomp($do_backup); + +# Add backup user principals to new Administrator role +if (@backup_user_principals && $do_backup =~ /y/i) { + my $user_administrator_role_url = "https://$hostname/netbackup/access-control/roles/0/relationships/user-principals"; + my $backup_users = encode_json(generate_user_principal_resource_identifier_objects(@backup_user_principals)); + $response = $http->post($user_administrator_role_url, 'Content-Type' => $media_type, Content => $backup_users); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to add backup admin users!\n" ; + } +} + +# Add backup group principals to new Administrator role +if (@backup_group_principals && $do_backup =~ /y/i) { + my $group_administrator_role_url = "https://$hostname/netbackup/access-control/roles/0/relationships/group-principals"; + my $backup_groups = encode_json(generate_group_principal_resource_identifier_objects(@backup_group_principals)); + $response = $http->post($group_administrator_role_url, 'Content-Type' => $media_type, Content => $backup_groups); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to add backup admin groups!\n" ; + } +} + +# Prompt user for security to Security Administrator migration confirmation +print "\n"; +if (@security_user_principals) { + print "Found the following security administrator principals:\n"; + foreach my $security_user(@security_user_principals) { + print "\t$security_user\n"; + } +} +if (@security_group_principals) { + print "Found the following security administrator group principals:\n"; + foreach my $security_group(@security_group_principals) { + print "\t$security_group\n"; + } +} + +my $accesscontrol_roles_url = "https://$hostname/netbackup/access-control/roles"; +$response = $http->get($accesscontrol_roles_url); +my $new_security_admin_role_id = extract_security_role_id($response); + +my $do_security; +if ($new_security_admin_role_id > 0) { + print "The Security Administrator role already exists.\nWould you like to migrate these principals to the existing Security Administrator role? (y/N) "; + $do_security = <>; + chomp($do_security); + if ($do_security !~ /y/i) { + exit; + } +} else { + print "\nWould you like to migrate these principals to a new Security Administrator role? (y/N) "; + $do_security = <>; + chomp($do_security); + + # Create new Security Administrator role + if ($do_security =~ /y/i) { + my $access_control_roles_url = "https://$hostname/netbackup/access-control/roles"; + my $security_role_admin_body = <<'EOL'; +{ + "data": { + "type": "accessControlRole", + "attributes": { + "name": "Security Administrator", + "description": "Security administrator with privileges for performing actions including access control, certificates, security settings etc." + } + } +} +EOL + $response = $http->post($access_control_roles_url, 'Content-Type' => $media_type, Content => $security_role_admin_body); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + + die "Failed to create security administrator role!\n" ; + } + my $response_content = decode_json($response->content); + $new_security_admin_role_id = $response_content->{data}{id}; + print "New Security Administrator role created with ID: ", $new_security_admin_role_id, "\n"; + } +} + +# Create access definitions for new Security Administrator role +if ($do_security =~ /y/i) { + for my $managed_object (keys %security_role_operation_map) { + my $access_definitions_url = "https://$hostname/netbackup/access-control/managed-objects/$managed_object/access-definitions"; + my $operations = $security_role_operation_map{$managed_object}; + my $access_definition_object = encode_json(generate_access_definition_object($new_security_admin_role_id, $managed_object, $operations)); + $response = $http->post($access_definitions_url, 'Content-Type' => $media_type, Content => $access_definition_object); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to create access definition for security administrator role!\n"; + } + } +} + +# Add security user principals to new Security Administrator role +if (@security_user_principals && $do_security =~ /y/i) { + my $user_security_role_url = "https://$hostname/netbackup/access-control/roles/$new_security_admin_role_id/relationships/user-principals"; + my $security_users = encode_json(generate_user_principal_resource_identifier_objects(@security_user_principals)); + $response = $http->post($user_security_role_url, 'Content-Type' => $media_type, Content => $security_users); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to add security admin users!\n" ; + } +} + +# Add security group principals to new Security Administrator role +if (@security_group_principals && $do_security =~ /y/i) { + my $group_security_role_url = "https://$hostname/netbackup/access-control/roles/$new_security_admin_role_id/relationships/group-principals"; + my $security_groups = encode_json(generate_group_principal_resource_identifier_objects(@security_group_principals)); + $response = $http->post($group_security_role_url, 'Content-Type' => $media_type, Content => $security_groups); + unless ($response->is_success) { + if ($debug) { + print Dumper($response); + } + die "Failed to add security admin groups!\n" ; + } +} + + +sub extract_role_ids { + my ($response) = @_; + my $content = decode_json($response->content); + my @data = $content->{data}; + my ($backup_id, $security_id); + foreach my $role (@{ $content->{data} }) { + if ($role->{attributes}{isSystemDefined}) { + if ($role->{attributes}{name} =~ "Backup administrator") { + $backup_id = $role->{id}; + } elsif ($role->{attributes}{name} =~ "Security administrator") { + $security_id = $role->{id}; + } + } + } + return ($backup_id, $security_id); +} + +sub extract_security_role_id { + my ($response) = @_; + my $content = decode_json($response->content); + my @data = $content->{data}; + foreach my $role (@{ $content->{data} }) { + if ($role->{attributes}{name} =~ /security\sadministrator/i) { + return $role->{id}; + } + } + + return -1; +} + +sub extract_principals { + my ($response) = @_; + my $content = decode_json($response->content); + my @data = $content->{data}; + my (@backup_users, @backup_groups, @security_users, @security_groups); + foreach my $access_rule (@{ $content->{data} }) { + if ($access_rule->{relationships}{role}{data}{id} == $old_backup_admin_role_id) { + if ($access_rule->{relationships}{userPrincipal}) { + push @backup_users, $access_rule->{relationships}{userPrincipal}{data}{id}; + } elsif ($access_rule->{relationships}{groupPrincipal}) { + push @backup_groups, $access_rule->{relationships}{groupPrincipal}{data}{id}; + } + } elsif ($access_rule->{relationships}{role}{data}{id} == $old_security_admin_role_id) { + if ($access_rule->{relationships}{userPrincipal}) { + push @security_users, $access_rule->{relationships}{userPrincipal}{data}{id}; + } elsif ($access_rule->{relationships}{groupPrincipal}) { + push @security_groups, $access_rule->{relationships}{groupPrincipal}{data}{id}; + } + } + } + return (\@backup_users, \@backup_groups, \@security_users, \@security_groups); +} + +sub remove_duplicates { + my ($backup_principals_ref, $security_principals_ref) = @_; + my @backup_principals = @{$backup_principals_ref}; + my @security_principals = @{$security_principals_ref}; + my @filtered_security_principals = grep !${ { map { $_, 1 } @backup_principals } }{ $_ }, @security_principals; + return \@filtered_security_principals; +} + +sub generate_user_principal_resource_identifier_objects { + my (@principals) = @_; + my @data; + foreach my $principal (@principals) { + my %identifier = (type => 'userPrincipal', id => $principal); + push @data, \%identifier; + } + my %objects = (data => \@data); + return \%objects; +} + +sub generate_group_principal_resource_identifier_objects { + my (@principals) = @_; + my @data; + foreach my $principal (@principals) { + my %identifier = (type => 'groupPrincipal', id => $principal); + push @data, \%identifier; + } + my %objects = (data => \@data); + return \%objects; +} + +sub generate_access_control_operation_resource_identifier_objects { + my (@operations) = @_; + my @data; + foreach my $operation (@operations) { + my %identifier = (type => 'accessControlOperation', id => $operation); + push @data, \%identifier; + } + my %objects = (data => \@data); + return \%objects; +} + +sub generate_access_definition_object { + my ($role_id, $managed_object, $operations_ref) = @_; + my @operations = @{$operations_ref}; + my %object = ( + data => { + type => "accessDefinition", + attributes => { + propagation => "OBJECT_AND_CHILDREN" + }, + relationships => { + role => { + data => { + type => "accessControlRole", + id => "$role_id" + } + }, + operations => generate_access_control_operation_resource_identifier_objects(@operations), + managed_object => { + data => { + type => "managedObject", + id => "$managed_object" + } + } + } + } + ); + return \%object; +} + + +__END__ + +=head1 NAME + +rbac_user_migration.pl - migrate pre-8.3 RBAC admin roles + +=head1 SYNOPSIS + +B [--debug] [--hostname master_server] [--username user] [--password secret] [--domain_type type] [--domain_name name] [--token JWT] [--help] [--man] + +=head1 DESCRIPTION + +B takes pre-8.3 RBAC admin roles and migrates them to the new RBAC framework. + +Backup admins are assigned to the default Administrator role. Security admins are assigned to a new Security Administrator role created by this script. + +An access definition is created for the new Security Administrator role using a suggested list of managed objects and operations. This list can be modified to suit your environment before running the script. + +Most configuration options can either be set in the script itself or passed as command line parameters. + +For more detailed information on RBAC please see the NetBackup Security & Encryption guide. + +To get the latest version of this script please check out the NetBackup API Code Samples repo on GitHub at L. + +=head1 DEPENDENCIES + +This script requires these other non-core modules: + +=over 4 + +=item LWP::Protocol::https + +=item LWP::UserAgent + +=item Net::SSLeay + +=back + +=head1 OPTIONS + +=over 4 + +=item B<-h, --help> + +Print a brief summary of the options to B and exit. + +=item B<-m, --man> + +Print the full manual page for B and exit. + +=item B<-d, --debug> + +Prints the full HTTP response object when an API call fails. Useful for debugging script execution problems. + +=item B<--host, --hostname> + +The hostname of the master server to run script against. This script can be run from any system as long as there is network connectivity to the master server specified. Defaults to 'localhost' if not specified. + +=item B<--user, --username> + +The API user to authenticate with on the master server. Required if token is not provided. + +=item B<--pass, --password> + +The password to authenticate with on the master server. Required if token is not provided. + +=item B<--domain_type> + +The domain type to authenticate with on the master server. + +=item B<--domain_name> + +The domain name to authenticate with on the master server. + +=item B<--token> + +The JWT or API key value to use instead of authenticating and creating a new user session. Required if username and password are not provided. + +=back + +=head1 EXAMPLES + +rbac_user_migration.pl --host nbumaster.domain.com --user dennis --pass secret --domain_type unixpwd + +rbac_user_migration.pl --host nbumaster.domain.com --user bill --pass secret --domain_type NT --domain_name DOMAIN + +rbac_user_migration.pl --host nbumaster.domain.com --token Iojwei38djasdf893n-23ds + +=head1 LICENSE AND COPYRIGHT + +Copyright 2020 Veritas Technologies LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +=cut diff --git a/recipes/perl/admin/README.md b/recipes/perl/admin/README.md new file mode 100755 index 0000000..5559f77 --- /dev/null +++ b/recipes/perl/admin/README.md @@ -0,0 +1,18 @@ +### NetBackup API Code Samples for perl + +This directory contains code samples to invoke NetBackup admininstration REST APIs using perl. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher +- Perl 5.20.2 or higher + +#### Executing the recipes in perl + +Use the following commands to run the perl samples. +- `perl get_processes.pl -nbmaster -username -password [-domainName ] [-domainType ] -client ` +- `perl get_services.pl -nbmaster -username -password [-domainName ] [-domainType ] -client ` diff --git a/recipes/perl/admin/get_processes.pl b/recipes/perl/admin/get_processes.pl new file mode 100755 index 0000000..998e3dd --- /dev/null +++ b/recipes/perl/admin/get_processes.pl @@ -0,0 +1,166 @@ +#!/usr/bin/env perl + +use LWP::UserAgent; +use LWP::Protocol::https; +print "LWP::UserAgent: ".LWP::UserAgent->VERSION,"\n"; +print "LWP::Protocol::https: ".LWP::Protocol::https->VERSION,"\n"; +use JSON; +use Getopt::Long qw(GetOptions); + +require 'api_requests.pl'; + +# +# The token is the key to the NetBackup AuthN/AuthZ scheme. You must login and get a token +# and use this token in your Authorization header for all subsequent requests. Token validity +# is fixed at 24 hours +# +my $token; + +my $content_type_v3 = "application/vnd.netbackup+json; version=3.0"; +my $protocol = "https"; +my $port = "1556"; +my $nbmaster; +my $username; +my $password; +my $domainName; +my $domainType; +my $token; +my $base_url; +my $client; + +my $ua = LWP::UserAgent->new( + ssl_opts => { verify_hostname => 0, verify_peer => 0}, + ); + +# subroutines for printing usage and library information required to run the script. +sub print_usage { + print("\n\nUsage:"); + print("\nperl get_processes -nbmaster -username -password [-domainName ] [-domainType ] -client \n\n\n"); +} + +sub print_disclaimer { + print("--------------------------------------------------------\n"); + print("-- This script requires Perl 5.20.2 or later --\n"); + print("--------------------------------------------------------\n"); + print("Executing this library requires some additional libraries like \n\t'LWP' \n\t'JSON'\ \n\t'Getopt'\ \n\n"); + print("You can specify the 'nbmaster', 'username', 'password', 'domainName', 'domainType' and 'client' as command-line parameters\n"); + print_usage(); +} + + +# subroutine to process user input +sub user_input { + GetOptions( + 'nbmaster=s' => \$nbmaster, + 'username=s' => \$username, + 'password=s' => \$password, + 'domainName=s' => \$domainName, + 'domainType=s' => \$domainType, + 'client=s' => \$client, + ) or die print_usage(); + + if ($nbmaster eq "") { + print("Please provide the value for 'nbmaster'"); + exit; + } + + if ($username eq "") { + print("Please provide the value for 'username'"); + exit; + } + + if ($password eq "") { + print("Please provide the value for 'password'"); + exit; + } + + if ($client eq "") { + print("Please provide the value for 'client'"); + exit; + } + + $base_url = "$protocol://$nbmaster:$port/netbackup"; +} + +# subroutine to get hostid for a given host name +sub get_hostid { + my $uuid; + my @argument_list = @_; + $host_name = $argument_list[0]; + + my $url = "$base_url/config/hosts?filter=hostName eq '$host_name'"; + my $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => $content_type_v3); + $req->header('Authorization' => $token); + print "\n\n**************************************************************"; + print "\n\n Making GET Request to get host id \n\n"; + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $message = $resp->decoded_content; + print "Get host succeeded with status code: ", $resp->code, "\n"; + my $json = decode_json($message); + my @hosts = @{$json->{'hosts'}}; + $uuid = @hosts[0]->{'uuid'}; + print "uuid=$uuid\n"; + } + else { + print "HTTP GET error code: ", $resp->code, "\n"; + print "HTTP GET error message: ", $resp->decoded_content, "\n"; + } + return $uuid; +} + +# subroutine to get processes +sub get_processes { + my @argument_list = @_; + my $uuid = $argument_list[0]; + my $url = "$base_url/admin/hosts/$uuid/processes"; + + my $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => $content_type_v3); + $req->header('Authorization' => $token); + + print "\n\n**************************************************************"; + print "\n\n Making GET Request to get processes\n\n"; + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $message = $resp->decoded_content; + print "Get processes succeeded with status code: ", $resp->code, "\n\n\n"; + print "Process List for NetBackup Client \"$client\"\n\n"; + print "pid processName priority memoryUsageMB startTime elapsedTime\n"; + print "=======.================.========.=============.======================.======================\n"; + + my $json = decode_json($message); + my @processes = @{$json->{'data'}}; + foreach (@processes) { + my $process = $_; + my $pid = $process->{'attributes'}->{'pid'}; + my $processName = $process->{'attributes'}->{'processName'}; + my $priority = $process->{'attributes'}->{'priority'}; + my $memoryUsageMB = $process->{'attributes'}->{'memoryUsageMB'}; + my $startTime = $process->{'attributes'}->{'startTime'}; + my $elapsedTime = $process->{'attributes'}->{'elapsedTime'}; + printf("%7s %-16s %8s %13s %22s %22s\n", $pid, $processName, $priority, $memoryUsageMB, $startTime, $elapsedTime); + } + } + else { + print "HTTP GET error code: ", $resp->code, "\n"; + print "HTTP GET error message: ", $resp->decoded_content, "\n"; + } +} + +print_disclaimer(); + +user_input(); + +$token = perform_login($base_url, $username, $password, $domainName, $domainType); + +my $uuid = get_hostid($client); +if ($uuid eq "") { + print("\nUnable to read host uuid for client $client\n"); + exit; +} + +get_processes($uuid); diff --git a/recipes/perl/admin/get_services.pl b/recipes/perl/admin/get_services.pl new file mode 100755 index 0000000..1cdecc8 --- /dev/null +++ b/recipes/perl/admin/get_services.pl @@ -0,0 +1,189 @@ +#!/usr/bin/env perl + +use LWP::UserAgent; +use LWP::Protocol::https; +print "LWP::UserAgent: ".LWP::UserAgent->VERSION,"\n"; +print "LWP::Protocol::https: ".LWP::Protocol::https->VERSION,"\n"; +use JSON; +use Getopt::Long qw(GetOptions); + +require 'api_requests.pl'; + +# +# The token is the key to the NetBackup AuthN/AuthZ scheme. You must login and get a token +# and use this token in your Authorization header for all subsequent requests. Token validity +# is fixed at 24 hours +# +my $token; + +my $content_type_v3 = "application/vnd.netbackup+json; version=3.0"; +my $protocol = "https"; +my $port = "1556"; +my $nbmaster; +my $username; +my $password; +my $domainName; +my $domainType; +my $token; +my $base_url; +my $client; + +my $ua = LWP::UserAgent->new( + ssl_opts => { verify_hostname => 0, verify_peer => 0}, + ); + +# subroutines for printing usage and library information required to run the script. +sub print_usage { + print("\n\nUsage:"); + print("\nperl get_services -nbmaster -username -password [-domainName ] [-domainType ] -client \n\n\n"); +} + +sub print_disclaimer { + print("--------------------------------------------------------\n"); + print("-- This script requires Perl 5.20.2 or later --\n"); + print("--------------------------------------------------------\n"); + print("Executing this library requires some additional libraries like \n\t'LWP' \n\t'JSON'\ \n\t'Getopt'\ \n\n"); + print("You can specify the 'nbmaster', 'username', 'password', 'domainName', 'domainType' and 'client' as command-line parameters\n"); + print_usage(); +} + + +# subroutine to process user input +sub user_input { + GetOptions( + 'nbmaster=s' => \$nbmaster, + 'username=s' => \$username, + 'password=s' => \$password, + 'domainName=s' => \$domainName, + 'domainType=s' => \$domainType, + 'client=s' => \$client, + ) or die print_usage(); + + if ($nbmaster eq "") { + print("Please provide the value for 'nbmaster'"); + exit; + } + + if ($username eq "") { + print("Please provide the value for 'username'"); + exit; + } + + if ($password eq "") { + print("Please provide the value for 'password'"); + exit; + } + + if ($client eq "") { + print("Please provide the value for 'client'"); + exit; + } + + $base_url = "$protocol://$nbmaster:$port/netbackup"; +} + +# subroutine to get hostid for a given host name +sub get_hostid { + my $uuid; + my @argument_list = @_; + $host_name = $argument_list[0]; + + my $url = "$base_url/config/hosts?filter=hostName eq '$host_name'"; + my $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => $content_type_v3); + $req->header('Authorization' => $token); + print "\n\n**************************************************************"; + print "\n\n Making GET Request to get host id \n\n"; + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $message = $resp->decoded_content; + print "Get host succeeded with status code: ", $resp->code, "\n"; + my $json = decode_json($message); + my @hosts = @{$json->{'hosts'}}; + $uuid = @hosts[0]->{'uuid'}; + print "uuid=$uuid\n"; + } + else { + print "HTTP GET error code: ", $resp->code, "\n"; + print "HTTP GET error message: ", $resp->decoded_content, "\n"; + } + return $uuid; +} + +# subroutine to get services +sub get_services { + my @argument_list = @_; + my $uuid = $argument_list[0]; + my $url = "$base_url/admin/hosts/$uuid/services"; + + my $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => $content_type_v3); + $req->header('Authorization' => $token); + + print "\n\n**************************************************************"; + print "\n\n Making GET Request to get services\n\n"; + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $message = $resp->decoded_content; + print "Get services succeeded with status code: ", $resp->code, "\n\n\n"; + print "Services List for NetBackup Client \"$client\"\n\n"; + print "id status\n"; + print "=======.================\n"; + + my $json = decode_json($message); + my @services = @{$json->{'data'}}; + foreach (@services) { + my $service = $_; + my $id = $service->{'id'}; + my $status = $service->{'attributes'}->{'status'}; + printf("%7s %-16s\n", $id, $status); + } + } + else { + print "HTTP GET error code: ", $resp->code, "\n"; + print "HTTP GET error message: ", $resp->decoded_content, "\n"; + } + + $url = "$base_url/admin/hosts/$uuid/services/bpcd"; + + $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => $content_type_v3); + $req->header('Authorization' => $token); + + print "\n\n**************************************************************"; + print "\n\n Making GET Request to get the service by name\n\n"; + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $message = $resp->decoded_content; + print "Get the service succeeded with status code: ", $resp->code, "\n\n\n"; + print "Services List for NetBackup Client \"$client\"\n\n"; + print "id status\n"; + print "=======.================\n"; + + my $json = decode_json($message); + $id = $json->{'data'}->{'id'}; + $status = $json->{'data'}->{'attributes'}->{'status'}; + printf("%7s %-16s\n", $id, $status); + } + else { + print "HTTP GET error code: ", $resp->code, "\n"; + print "HTTP GET error message: ", $resp->decoded_content, "\n"; + } +} + +print_disclaimer(); + +user_input(); + +$token = perform_login($base_url, $username, $password, $domainName, $domainType); + +my $uuid = get_hostid($client); +if ($uuid eq "") { + print("\nUnable to read host uuid for client $client\n"); + exit; +} + +get_services($uuid); diff --git a/recipes/perl/assets/README.md b/recipes/perl/assets/README.md new file mode 100755 index 0000000..5693885 --- /dev/null +++ b/recipes/perl/assets/README.md @@ -0,0 +1,28 @@ +### NetBackup API Code Samples for perl + +This directory contains code samples to invoke NetBackup VMware Assets API using perl. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Prerequisites: + +- NetBackup 8.3 or higher +- Perl 5.20.2 or higher + +#### Executing the recipes in perl + +Use the following commands to run the scripts. + +- `perl get_vmware_assets.pl -nbmaster -username -password [-domainName ] [-domainType ]` + +The script uses the NetBackup Asset Service API to get VMware assets (first page of records) and prints the assetIDs. + +- `perl create_assetGroup.pl -nbmaster -username -password [-domainName ] [-domainType ]` + +The script creates a sample VMware asset group in NetBackup by using the asset service API. + +Examples: +- perl get_vmware_assets.pl -nbmaster localhost -username user -password password -domainName domain -domainType NT +- perl create_assetGroup.pl -nbmaster localhost -username user -password password -domainName domain -domainType NT diff --git a/recipes/perl/assets/create_assetGroup.pl b/recipes/perl/assets/create_assetGroup.pl new file mode 100755 index 0000000..607ba23 --- /dev/null +++ b/recipes/perl/assets/create_assetGroup.pl @@ -0,0 +1,206 @@ +#!/usr/bin/env perl + +use LWP::UserAgent; +use LWP::Protocol::https; +print "LWP::UserAgent: ".LWP::UserAgent->VERSION,"\n"; +print "LWP::Protocol::https: ".LWP::Protocol::https->VERSION,"\n"; +use JSON; +use Getopt::Long qw(GetOptions); + + +# +# The token is the key to the NetBackup AuthN/AuthZ scheme. You must login and get a token +# and use this token in your Authorization header for all subsequent requests. Token validity +# is fixed at 24 hours +# + +my $content_type = "application/vnd.netbackup+json; version=4.0"; +my $protocol = "https"; +my $port = "1556"; +my $nbmaster; +my $username; +my $password; +my $domainName; +my $domainType; +my $token; +my $base_url; + +my $ua = LWP::UserAgent->new( + ssl_opts => { verify_hostname => 0, verify_peer => 0}, + ); + +# subroutines for printing usage and library information required to run the script. +sub print_usage { + print("\n\nUsage:"); + print("\nperl get_vmware_assets -nbmaster -username -password [-domainName ] [-domainType ] \n\n\n"); +} + +sub print_disclaimer { + print("--------------------------------------------------------\n"); + print("-- This script requires Perl 5.20.2 or later --\n"); + print("--------------------------------------------------------\n"); + print("Executing this library requires some additional libraries like \n\t'LWP' \n\t'JSON'\ \n\t'Getopt'\ \n\n"); + print("You can specify the 'nbmaster', 'username', 'password', 'domainName', 'domainType' as command-line parameters\n"); + print_usage(); +} + + +# subroutine to process user input +sub user_input { + GetOptions( + 'nbmaster=s' => \$nbmaster, + 'username=s' => \$username, + 'password=s' => \$password, + 'domainName=s' => \$domainName, + 'domainType=s' => \$domainType, + ) or (print_usage() && exit); + + if ($nbmaster eq "") { + print("Please provide the value for 'nbmaster'"); + exit; + } + + if ($username eq "") { + print("Please provide the value for 'username'"); + exit; + } + + if ($password eq "") { + print("Please provide the value for 'password'"); + exit; + } + + $base_url = "$protocol://$nbmaster:$port/netbackup"; +} + +sub login { + my @argument_list = @_; + $base_url = $argument_list[0]; + my $username = $argument_list[1]; + my $password = $argument_list[2]; + my $domainName = $argument_list[3]; + my $domainType = $argument_list[4]; + + my $url = "$base_url/login"; + + my $req = HTTP::Request->new(POST => $url); + $req->header('content-type' => 'application/json'); + + if ($domainName eq "" && $domainType eq "") { + $post_data = qq({ "userName": "$username", "password": "$password" }); + } + else { + $post_data = qq({ "domainType": "$domainType", "domainName": "$domainName", "userName": "$username", "password": "$password" }); + } + $req->content($post_data); + + + print "\n\n**************************************************************"; + print "\n\n Making POST Request to login to get token \n\n"; + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $message = decode_json($resp->content); + $token = $message->{"token"}; + print "Login succeeded with status code: ", $resp->code, "\n"; + } + else { + print "Request failed with status code: ", $resp->code, "\n"; + } + return $token; +} + +# subroutine to Create Asset Group +sub create_assetGroup { + my $url = "$base_url/asset-service/queries"; + + my $asset_data = qq({ + "data": { + "type": "query", + "attributes": { + "queryName": "create-or-update-assets", + "workloads": ["vmware"], + "parameters": { + "objectList": [ + { + "correlationId": "cor-1234", + "type": "vmwareGroupAsset", + "assetGroup": { + "description": "sampleDescription", + "assetType": "vmGroup", + "filterConstraint": "sampleFilterConstaint", + "oDataQueryFilter": "commonAssetAttributes/displayName eq 'testing1234'", + "commonAssetAttributes": { + "displayName": "sampleGroup1234", + "workloadType": "vmware", + "protectionCapabilities": { + "isProtectable": "YES", + "isProtectableReason": "sampleReason", + "isRecoverable": "NO", + "isRecoverableReason": "sampleReason" + }, + "detection": { + "detectionMethod": "MANUAL" + } + } + } + } + ] + } + } + } +}); + + my $req = HTTP::Request->new(POST => $url); + $req->header('Content-Type' => $content_type); + $req->header('Authorization' => $token); + $req->content($asset_data); + + print "\n\n**************************************************************"; + print "\n\n Making POST Request to create assetGroup\n\n"; + + my $resp = $ua->request($req); + + my $message = $resp->decoded_content; + print "Create vmware Asset Group succeeded with status code: ", $resp->code, "\n\n\n"; + print "=======================\n"; + + my $json = decode_json($message); + my $id = $json->{'data'}->{'id'}; + print "id: ", $id, "\n\n\n"; + + my $url = "$base_url/asset-service/queries/$id"; + my $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => $content_type); + $req->header('Authorization' => $token); + + print "\n\n**************************************************************"; + print "\n\n Making GET Request for the QueryID response\n\n"; + + my $resp = $ua->request($req); + my $message = $resp->decoded_content; + + print "Create vmware Asset Group query id : ", $resp->code, "\n\n\n"; + + my $json = decode_json($message); + my @responses = @{$json->{'data'}}; + for my $response (@responses) { + my @workitems = @{$response->{'attributes'}->{'workItemResponses'}}; + for my $workItem (@workitems) { + my $status = $workItem->{'statusDetails'}->{'message'}; + if ($status eq 'Created') { + print "VMware Asset Group : ", $status ,"\n"; + } else { + print "VMware Asset Group Not Created due to: ", $status ,"\n"; + } + } + } +} + +print_disclaimer(); + +user_input(); + +$token = login($base_url, $username, $password, $domain_name, $domain_type); + +create_assetGroup(); diff --git a/recipes/perl/assets/get_vmware_assets.pl b/recipes/perl/assets/get_vmware_assets.pl new file mode 100755 index 0000000..3cd0540 --- /dev/null +++ b/recipes/perl/assets/get_vmware_assets.pl @@ -0,0 +1,152 @@ +#!/usr/bin/env perl + +use LWP::UserAgent; +use LWP::Protocol::https; +print "LWP::UserAgent: ".LWP::UserAgent->VERSION,"\n"; +print "LWP::Protocol::https: ".LWP::Protocol::https->VERSION,"\n"; +use JSON; +use Getopt::Long qw(GetOptions); + + +# +# The token is the key to the NetBackup AuthN/AuthZ scheme. You must login and get a token +# and use this token in your Authorization header for all subsequent requests. Token validity +# is fixed at 24 hours +# + +my $content_type = "application/vnd.netbackup+json; version=4.0"; +my $protocol = "https"; +my $port = "1556"; +my $nbmaster; +my $username; +my $password; +my $domainName; +my $domainType; +my $token; +my $base_url; +my $assetsFilter; + +my $ua = LWP::UserAgent->new( + ssl_opts => { verify_hostname => 0, verify_peer => 0}, + ); + +# subroutines for printing usage and library information required to run the script. +sub print_usage { + print("\n\nUsage:"); + print("\nperl get_vmware_assets -nbmaster -username -password [-domainName ] [-domainType ] [-assetsFilter ]\n\n\n"); +} + +sub print_disclaimer { + print("--------------------------------------------------------\n"); + print("-- This script requires Perl 5.20.2 or later --\n"); + print("--------------------------------------------------------\n"); + print("Executing this library requires some additional libraries like \n\t'LWP' \n\t'JSON'\ \n\t'Getopt'\ \n\n"); + print("You can specify the 'nbmaster', 'username', 'password', 'domainName', 'domainType' and 'assetsFilter' as command-line parameters\n"); + print_usage(); +} + +# subroutine to process user input +sub user_input { + GetOptions( + 'nbmaster=s' => \$nbmaster, + 'username=s' => \$username, + 'password=s' => \$password, + 'domainName=s' => \$domainName, + 'domainType=s' => \$domainType, + ) or (print_usage() && exit); + + if ($nbmaster eq "") { + print("Please provide the value for 'nbmaster'"); + exit; + } + + if ($username eq "") { + print("Please provide the value for 'username'"); + exit; + } + + if ($password eq "") { + print("Please provide the value for 'password'"); + exit; + } + + $base_url = "$protocol://$nbmaster:$port/netbackup"; +} + +sub login { + my @argument_list = @_; + $base_url = $argument_list[0]; + my $username = $argument_list[1]; + my $password = $argument_list[2]; + my $domainName = $argument_list[3]; + my $domainType = $argument_list[4]; + + my $url = "$base_url/login"; + + my $req = HTTP::Request->new(POST => $url); + $req->header('content-type' => 'application/json'); + + if ($domainName eq "" && $domainType eq "") { + $post_data = qq({ "userName": "$username", "password": "$password" }); + } + else { + $post_data = qq({ "domainType": "$domainType", "domainName": "$domainName", "userName": "$username", "password": "$password" }); + } + $req->content($post_data); + + + print "\n\n**************************************************************"; + print "\n\n Making POST Request to login to get token \n\n"; + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $message = decode_json($resp->content); + $token = $message->{"token"}; + print "Login succeeded with status code: ", $resp->code, "\n"; + } + else { + print "Request failed with status code: ", $resp->code, "\n"; + } + return $token; +} + +# subroutine to get assets +sub get_assets { + my $url = "$base_url/asset-service/workloads/vmware/assets"; + + my $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => $content_type); + $req->header('Authorization' => $token); + + print "\n\n**************************************************************"; + print "\n\n Making GET Request to get assets\n\n"; + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $message = $resp->decoded_content; + print "Get vmware Assets succeeded with status code: ", $resp->code, "\n\n\n"; + print "Below is the list of asset IDs:\n"; + print "=======================\n"; + + my $json = decode_json($message); + my @assets = @{$json->{'data'}}; + foreach (@assets) { + my $asset = $_; + my $id = $asset->{'id'}; + printf("Asset id : %s \n", $id); + + } + } + else { + print "HTTP GET error code: ", $resp->code, "\n"; + print "HTTP GET error message: ", $resp->decoded_content, "\n"; + } +} + +print_disclaimer(); + +user_input(); + +$token = login($base_url, $username, $password, $domain_name, $domain_type); + +get_assets(); diff --git a/recipes/perl/config/README.md b/recipes/perl/config/README.md new file mode 100755 index 0000000..c480dd1 --- /dev/null +++ b/recipes/perl/config/README.md @@ -0,0 +1,17 @@ +### NetBackup API Code Samples for perl + +This directory contains code samples to invoke NetBackup configuration REST APIs using perl. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher +- Perl 5.20.2 or higher + +#### Executing the recipes in perl + +Use the following commands to run the perl samples. +- `perl get_set_host_config.pl -nbmaster -username -password [-domainName ] [-domainType ] -client ` diff --git a/recipes/perl/config/get_set_host_config.pl b/recipes/perl/config/get_set_host_config.pl new file mode 100755 index 0000000..3f815af --- /dev/null +++ b/recipes/perl/config/get_set_host_config.pl @@ -0,0 +1,96 @@ +#!/usr/bin/env perl + +use LWP::UserAgent; +use LWP::Protocol::https; +use JSON; +use Getopt::Long qw(GetOptions); + +require 'api_requests.pl'; + +print "LWP::UserAgent: ".LWP::UserAgent->VERSION,"\n"; +print "LWP::Protocol::https: ".LWP::Protocol::https->VERSION,"\n"; + +# +# The token is the key to the NetBackup AuthN/AuthZ scheme. You must login and get a token +# and use this token in your Authorization header for all subsequent requests. Token validity +# is fixed at 24 hours +# + +my $nbmaster; +my $username; +my $password; +my $domainName; +my $domainType; +my $protocol = "https"; +my $port = "1556"; +my $base_url; + +my $ua = LWP::UserAgent->new( + ssl_opts => { verify_hostname => 0, verify_peer => 0}, + ); + +# subroutines for printing usage and library information required to run the script. +sub print_usage { + print("\n\nUsage:"); + print("\nperl get_set_host_config.pl -nbmaster -username -password [-domainName ] [-domainType ] -client \n\n\n"); +} + +sub print_disclaimer { + print("--------------------------------------------------------\n"); + print("-- This script requires Perl 5.20.2 or later --\n"); + print("--------------------------------------------------------\n"); + print("Executing this library requires some additional libraries like \n\t'LWP' \n\t'JSON'\ \n\t'Getopt'\ \n\n"); + print("You can specify the 'nbmaster', 'username', 'password', 'domainName', 'domainType', and 'client' as command-line parameters\n"); + print_usage(); +} + + +# subroutine to process user input +sub user_input { + GetOptions( + 'nbmaster=s' => \$nbmaster, + 'username=s' => \$username, + 'password=s' => \$password, + 'domainName=s' => \$domainName, + 'domainType=s' => \$domainType, + 'client=s' => \$client, + ) or die print_usage(); + + if ($nbmaster eq "") { + print("Please provide the value for 'nbmaster'"); + exit; + } + + if ($username eq "") { + print("Please provide the value for 'username'"); + exit; + } + + if ($password eq "") { + print("Please provide the value for 'password'"); + exit; + } + + if ($client eq "") { + print("Please provide the value for 'client'"); + exit; + } + + $base_url = "$protocol://$nbmaster:$port/netbackup"; +} + +sub get_set_config { + get_exclude_list($host_uuid); + set_exclude_list($host_uuid); + get_exclude_list($host_uuid); +} + +print_disclaimer(); + +user_input(); + +perform_login($base_url, $username, $password, $domainName, $domainType); + +my $host_uuid = get_host_uuid($client); + +get_set_config(); diff --git a/recipes/perl/images/README.md b/recipes/perl/images/README.md new file mode 100755 index 0000000..c9288bd --- /dev/null +++ b/recipes/perl/images/README.md @@ -0,0 +1,18 @@ +### NetBackup API Code Samples for perl + +This directory contains code samples to invoke NetBackup images REST APIs using perl. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.1.2 or higher +- Perl 5.20.2 or higher + +#### Executing the recipes in perl + +Use the following commands to run the perl samples. +- `perl api_requests_images.pl -nbmaster -username -password [-domainName ] [-domainType ]` +- `perl api_requests_image_contents.pl -nbmaster -username -password [-domainName ] [-domainType ]` diff --git a/recipes/perl/api_requests_image_contents.pl b/recipes/perl/images/api_requests_image_contents.pl similarity index 100% rename from recipes/perl/api_requests_image_contents.pl rename to recipes/perl/images/api_requests_image_contents.pl diff --git a/recipes/perl/api_requests_images.pl b/recipes/perl/images/api_requests_images.pl similarity index 100% rename from recipes/perl/api_requests_images.pl rename to recipes/perl/images/api_requests_images.pl diff --git a/recipes/perl/README.md b/recipes/perl/policies/README.md old mode 100644 new mode 100755 similarity index 67% rename from recipes/perl/README.md rename to recipes/perl/policies/README.md index ab1139a..5b46939 --- a/recipes/perl/README.md +++ b/recipes/perl/policies/README.md @@ -1,6 +1,6 @@ ### NetBackup API Code Samples for perl -This directory contains code samples to invoke NetBackup REST APIs using perl. +This directory contains code samples to invoke NetBackup policies REST APIs using perl. #### Disclaimer @@ -9,6 +9,12 @@ These scripts are only meant to be used as a reference. If you intend to use the #### Pre-requisites: - NetBackup 8.1.2 or higher + + - **NOTE:** The following scripts configure access control using the old RBAC design and will only work on NetBackup + release 8.1.2 or 8.2. + - recipes/perl/policies/api_requests_rbac_policy.pl + - recipes/perl/policies/rbac_filtering_in_policy.pl + - Perl 5.20.2 or higher #### Executing the recipes in perl @@ -17,5 +23,3 @@ Use the following commands to run the perl samples. - `perl create_policy_step_by_step.pl -nbmaster -username -password [-domainName ] [-domainType ]` - `perl create_policy_in_one_step.pl -nbmaster -username -password [-domainName ] [-domainType ]` - `perl rbac_filtering_in_policy.pl -nbmaster -username -password [-domainName ] [-domainType ]` -- `perl api_requests_images.pl -nbmaster -username -password [-domainName ] [-domainType ]` -- `perl api_requests_image_contents.pl -nbmaster -username -password [-domainName ] [-domainType ]` diff --git a/recipes/perl/api_requests_rbac_policy.pl b/recipes/perl/policies/api_requests_rbac_policy.pl similarity index 100% rename from recipes/perl/api_requests_rbac_policy.pl rename to recipes/perl/policies/api_requests_rbac_policy.pl diff --git a/recipes/perl/create_policy_in_one_step.pl b/recipes/perl/policies/create_policy_in_one_step.pl similarity index 100% rename from recipes/perl/create_policy_in_one_step.pl rename to recipes/perl/policies/create_policy_in_one_step.pl diff --git a/recipes/perl/create_policy_step_by_step.pl b/recipes/perl/policies/create_policy_step_by_step.pl similarity index 100% rename from recipes/perl/create_policy_step_by_step.pl rename to recipes/perl/policies/create_policy_step_by_step.pl diff --git a/recipes/perl/rbac_filtering_in_policy.pl b/recipes/perl/policies/rbac_filtering_in_policy.pl similarity index 100% rename from recipes/perl/rbac_filtering_in_policy.pl rename to recipes/perl/policies/rbac_filtering_in_policy.pl diff --git a/recipes/perl/storage/README.md b/recipes/perl/storage/README.md new file mode 100644 index 0000000..9dadd15 --- /dev/null +++ b/recipes/perl/storage/README.md @@ -0,0 +1,17 @@ +### NetBackup API Code Samples for perl + +This directory contains code samples to invoke NetBackup REST APIs using perl. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher +- Perl 5.20.2 or higher + +#### Executing the recipes in perl + +Use the following commands to run the perl samples. +- `perl configure_storage_unit_cloud_end_to_end.pl -nbmaster -username -password -sts_payload -dp_payload -stu_payload [-domainName ] [-domainType ]` diff --git a/recipes/perl/storage/configure_storage_unit_end_to_end.pl b/recipes/perl/storage/configure_storage_unit_end_to_end.pl new file mode 100644 index 0000000..c5a32e0 --- /dev/null +++ b/recipes/perl/storage/configure_storage_unit_end_to_end.pl @@ -0,0 +1,109 @@ +#!/usr/bin/env perl + +use LWP::UserAgent; +use LWP::Protocol::https; +print "LWP::UserAgent: ".LWP::UserAgent->VERSION,"\n"; +print "LWP::Protocol::https: ".LWP::Protocol::https->VERSION,"\n"; +use JSON; +use Getopt::Long qw(GetOptions); +use storage; + +# This script consists of the helper functions to excute NetBackup APIs to create storage unit. +# 1) Login to Netbackup +# 2) Create storage server +# 3) Create disk Pool +# 4) Create storage unit + +# +# The token is the key to the NetBackup AuthN/AuthZ scheme. You must login and get a token +# and use this token in your Authorization header for all subsequent requests. Token validity +# is fixed at 24 hours +# +my $token; + +my $protocol = "https"; +my $port = "1556"; +my $nbmaster; +my $username; +my $password; +my $sts_payload; +my $dp_payload; +my $stu_payload; +my $domainName; +my $domainType; +my $base_url; + + +# subroutines for printing usage and library information required to run the script. +sub print_usage { + print("\n\nUsage:"); + print("\nperl configure_storage_unit_cloud_end_to_end.pl -nbmaster -username -password -sts_payload -dp_payload -stu_payload [-domainName ] [-domainType ]\n\n\n"); +} + +sub print_disclaimer { + print("--------------------------------------------------------\n"); + print("-- This script requires Perl 5.20.2 or later --\n"); + print("--------------------------------------------------------\n"); + print("Executing this library requires some additional libraries like \n\t'LWP' \n\t'JSON'\ \n\t'Getopt'\ \n\n"); + print("You can specify the 'nbmaster', 'username', 'password', 'sts_payload', 'dp_payload', 'stu_payload', 'domainName' and 'domainType' as command-line parameters\n"); + print_usage(); +} + +# subroutine to process user input +sub user_input { + GetOptions( + 'nbmaster=s' => \$nbmaster, + 'username=s' => \$username, + 'password=s' => \$password, + 'sts_payload=s' => \$sts_payload, + 'dp_payload=s' => \$dp_payload, + 'stu_payload=s' => \$stu_payload, + 'domainName=s' => \$domainName, + 'domainType=s' => \$domainType, + ) or die print_usage(); + + if ($nbmaster eq "") { + print("Please provide the value for 'nbmaster'"); + exit; + } + + if ($username eq "") { + print("Please provide the value for 'username'"); + exit; + } + + if ($password eq "") { + print("Please provide the value for 'password'"); + exit; + } + if ($sts_payload eq "") { + print("Please provide the value for 'sts_payload'"); + exit; + } + + if ($dp_payload eq "") { + print("Please provide the value for 'dp_payload'"); + exit; + } + + if ($stu_payload eq "") { + print("Please provide the value for 'stu_payload'"); + exit; + } + + $base_url = "$protocol://$nbmaster:$port/netbackup"; +} + +sub storage_api_automation { + my $token = storage::perform_login($nbmaster, $username, $password, $domain_name, $domain_type); + storage::post_storage_server($nbmaster, $token, $sts_payload); + storage::post_disk_pool($nbmaster, $token, $dp_payload); + storage::post_storage_unit($nbmaster, $token, $stu_payload); + +} + +print_disclaimer(); + +user_input(); + +storage_api_automation(); \ No newline at end of file diff --git a/recipes/perl/storage/storage.pm b/recipes/perl/storage/storage.pm new file mode 100644 index 0000000..caec679 --- /dev/null +++ b/recipes/perl/storage/storage.pm @@ -0,0 +1,244 @@ +#!/usr/bin/env perl + +package storage; + +use JSON; +use warnings; +use LWP::UserAgent; +use HTTP::Request; +use LWP::Protocol::https; + +$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0; +$CONTENT_TYPE = "application/vnd.netbackup+json;version=3.0"; +$PROTOCOL = "https://"; +$NB_PORT = 1556; + +my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0, verify_peer => 0}); + + +sub send_http_request { + my $url = $_[0]; + my $request_type = $_[1]; + my $token = $_[2]; + my $body = $_[3]; + my $accept = $_[4]; + my $content_type = $_[5]; + + if (not defined $url or not defined $request_type){ + print "Error: url and request type are required fields"; + return undef; + } + + print "Unencoded URL is $url\n"; + # assume string is un-encoded, and '%' is a literal that needs to be replaced by '%25'. + # All other types of encoding are handled gracefully by the LWP module except literal percent + $url =~ s/%/%25/; + + # determine correct request type + my $req; + if (uc($request_type) eq "GET" ){ + $req = HTTP::Request->new(GET => $url); + } + elsif ((uc($request_type) eq "POST")){ + $req = HTTP::Request->new(POST => $url); + } + elsif ((uc($request_type) eq "DELETE")){ + $req = HTTP::Request->new(DELETE => $url); + } + elsif ((uc($request_type) eq "PUT")) { + $req = HTTP::Request->new(PUT => $url); + } + elsif ((uc($request_type) eq "PATCH")){ + $req = HTTP::Request->new(PATCH => $url); + } + else { + print "Unrecognized request type [$request_type]. If this is a valid HTTP request type, please update me"; + return undef; + } + + # print encoded url to the screen + print "Encoded URL is ${$req->uri}\n"; + + if (defined $token) { + $req->header('Authorization' => $token); + } + if (defined $accept) { + $req->header('Accept' => $accept); + } + if (defined $content_type){ + $req->header('Content-Type' => $content_type); + } + if (defined $body){ + $req->content($body); + } + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $json_results; + if (defined($resp->content) && $resp->content ne "") { + $json_results = decode_json($resp->content); + } + else { + $json_results = ""; + } + return $json_results; + } + else { + print "HTTP error code: ", $resp->code, "\n"; + print "HTTP response content: ", $resp->content, "\n"; + return undef; + } +} + +sub perform_login { + my @argument_list = @_; + my $master_server = $argument_list[0]; + my $username = $argument_list[1]; + my $password = $argument_list[2]; + + my $token; + + # domainName and domainType are optional + my $domainName = ""; + my $domainType = ""; + if (@argument_list >= 4) { + $domainName = $argument_list[3]; + } + if (@argument_list == 5) { + $domainType = $argument_list[4]; + } + + # Construct url + my $url = "https://$master_server:1556/netbackup/login"; + + # Construct request body + my $post_data; + if (not $domainName and not $domainType) { + $post_data = qq({ "userName": "$username", "password": "$password" }); + } + else { + $post_data = qq({ "domainType": "$domainType", "domainName": "$domainName", "userName": "$username", "password": "$password" }); + } + + print "\n\n**************************************************************"; + print "\n\n Making POST Request to login to get token \n\n"; + + my $json_results = send_http_request($url, "post", undef, $post_data, undef, "application/json"); + + if (defined $json_results){ + $token = $json_results->{"token"}; + } + return $token; +} + +# Create a storage server +sub post_storage_server { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to post_storage_server()\n"; + print "Usage : post_storage_server( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-servers"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = send_http_request($url, "POST", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed POST Storage Server Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: POST Storage Server Request Failed!\n"; + } +} + + +# Create a storage unit +sub post_storage_unit { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to post_storage_unit()\n"; + print "Usage : post_storage_server( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-units"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = send_http_request($url, "POST", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed POST Storage Unit Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: POST Storage Unit Request Failed!\n"; + } +} + +# Create a Disk Pool +sub post_disk_pool { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to post_disk_pool()\n"; + print "Usage : post_storage_server( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/disk-pools"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = send_http_request($url, "POST", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed POST Disk Pool Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: POST Disk Pool Request Failed!\n"; + } +} + +1; + diff --git a/recipes/perl/api_requests.pl b/recipes/perl/utils/api_requests.pl similarity index 75% rename from recipes/perl/api_requests.pl rename to recipes/perl/utils/api_requests.pl index ca050cd..891d4d9 100755 --- a/recipes/perl/api_requests.pl +++ b/recipes/perl/utils/api_requests.pl @@ -1,8 +1,10 @@ #!/usr/bin/env perl use LWP::UserAgent; use JSON; +use Try::Tiny; my $content_type_v2 = "application/vnd.netbackup+json; version=2.0"; +my $content_type_v3 = "application/vnd.netbackup+json; version=3.0"; #We will get this token using login api and the token will be used #in subsequent api requests of policy @@ -50,8 +52,7 @@ sub perform_login { print "Login succeeded with status code: ", $resp->code, "\n"; } else { - print "HTTP POST error code: ", $resp->code, "\n"; - print "HTTP POST error message: ", $resp->message, "\n"; + printErrorResponse($resp); } return $token; } @@ -78,8 +79,7 @@ sub create_policy_with_defaults { print "Policy [$policy_name] with default values is create with status code: ", $resp->code, "\n"; } else { - print "HTTP POST error code: ", $resp->code, "\n"; - print "HTTP POST error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -122,8 +122,7 @@ sub create_policy { print "Policy [$policy_name] without default values is created with status code: ", $resp->code, "\n"; } else { - print "HTTP POST error code: ", $resp->code, "\n"; - print "HTTP POST error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -145,8 +144,7 @@ sub list_policies { print "Compact Json body for list policy: \n", $message, "\n\n"; } else { - print "HTTP GET error code: ", $resp->code, "\n"; - print "HTTP GET error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -171,8 +169,7 @@ sub read_policy { print "Respnse headers: \n", $resp->headers()->as_string, "\n\n"; } else { - print "HTTP GET error code: ", $resp->code, "\n"; - print "HTTP GET error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -191,8 +188,7 @@ sub read_policy_extract_Generation_Number_From_Response { $generation = $resp->header('ETag'); } else { - print "HTTP GET error code: ", $resp->code, "\n"; - print "HTTP GET error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -225,8 +221,7 @@ sub add_clients { print "Client is added to policy [$policy_name] with status code: ", $resp->code, "\n"; } else { - print "HTTP PUT error code: ", $resp->code, "\n"; - print "HTTP PUT error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -258,8 +253,7 @@ sub add_backupselections { print "BackupSelection is added to policy [$policy_name] with status code: ", $resp->code, "\n"; } else { - print "HTTP PUT error code: ", $resp->code, "\n"; - print "HTTP PUT error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -302,8 +296,7 @@ sub add_schedule { print "Schedule [$schedule_name] is added to policy [$policy_name] with status code: ", $resp->code, "\n"; } else { - print "HTTP PUT error code: ", $resp->code, "\n"; - print "HTTP PUT error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -331,8 +324,7 @@ sub delete_client { print "Client [MEDIA_SERVER] is deleted from policy [$policy_name] with status code: ", $resp->code, "\n"; } else { - print "HTTP DELETE error code: ", $resp->code, "\n"; - print "HTTP DELETE error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -361,8 +353,7 @@ sub delete_schedule { print "Schedule [$schedule_name] is deleted from policy [$policy_name] with status code: ", $resp->code, "\n"; } else { - print "HTTP DELETE error code: ", $resp->code, "\n"; - print "HTTP DELETE error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } @@ -398,9 +389,135 @@ sub delete_policy { print "Policy [$policy_name] is deleted with status code: ", $resp->code, "\n"; } else { - print "HTTP DELETE error code: ", $resp->code, "\n"; - print "HTTP DELETE error message: ", $resp->message, "\n"; + printErrorResponse($resp); } } -1; \ No newline at end of file +sub get_host_uuid { + + my @argument_list = @_; + $host = $argument_list[0]; + my $host_url = "$base_url/config/hosts?filter=hostName eq '$host'"; + + print "\n\n**************************************************************"; + print "\n\n Get the UUID for host ", $host, "\n\n"; + + my $req = HTTP::Request->new(GET => $host_url); + $req->header('Authorization' => $token); + $req->header('Accept' => $content_type_v3); + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $payload = decode_json($resp->content); + $host_uuid = $payload->{"hosts"}->[0]->{"uuid"}; + print "Host UUID: ", $host_uuid, "\n"; + } + else { + printErrorResponse($resp); + } + + return $host_uuid; +} + +sub get_exclude_list { + + my @argument_list = @_; + $hostuuid = $argument_list[0]; + my $exclude_url = "$base_url/config/hosts/$hostuuid/configurations/exclude"; + + print "\n\n**************************************************************"; + print "\n\n Get exclude list for the host ", $hostuuid, "\n\n"; + + my $req = HTTP::Request->new(GET => $exclude_url); + $req->header('Authorization' => $token); + + my $resp = $ua->request($req); + if ($resp->is_success) { + my $payload = decode_json($resp->content); + my $exclude_list= $payload->{"data"}->{"attributes"}->{"value"}; + + for my $item( @{$exclude_list} ){ + print $item. "\n"; + }; + } + else { + printErrorResponse($resp); + } + + return $exclude_list; +} + +sub set_exclude_list { + + my @argument_list = @_; + $hostuuid = $argument_list[0]; + my $exclude_url = "$base_url/config/hosts/$hostuuid/configurations/exclude"; + + print "\n\n**************************************************************"; + print "\n\n Set exclude list for the host ", $hostuuid, "\n\n"; + + my $exclude_list = qq({ "data": { + "type": "hostConfiguration", + "attributes": { + "name": "exclude", + "value": ["C:\\\\Program Files\\\\Veritas\\\\NetBackup\\\\bin\\\\*.lock", + "C:\\\\Program Files\\\\Veritas\\\\NetBackup\\\\bin\\\\bprd.d\\\\*.lock", + "C:\\\\Program Files\\\\Veritas\\\\NetBackup\\\\bin\\\\bpsched.d\\\\*.lock", + "C:\\\\Program Files\\\\Veritas\\\\Volmgr\\\\misc\\\\*", + "C:\\\\Program Files\\\\Veritas\\\\NetBackupDB\\\\data\\\\*", + "C:\\\\tmp"] + } + } + }); + $req = HTTP::Request->new(PUT => $exclude_url); + $req->header('Authorization' => $token); + $req->header('content-type' => $content_type_v3); + $req->content($exclude_list); + + $resp = $ua->request($req); + if ($resp->is_success) { + print "Exclude list was configured successfully. \n"; + } + else { + if ($resp->code == 404) { + my $config_url = "$base_url/config/hosts/$hostuuid/configurations"; + + $req = HTTP::Request->new(POST => $config_url); + $req->header('Authorization' => $token); + $req->header('content-type' => $content_type_v3); + $req->content($exclude_list); + + $resp = $ua->request($req); + if ($resp->is_success) { + print "Exclude list was configured successfully. \n"; + } + else { + printErrorResponse($resp); + } + } + else { + printErrorResponse($resp); + } + } +} + +sub printErrorResponse { + my @argument_list = @_; + $resp = $argument_list[0]; + + print "Request failed with status code: ", $resp->code, "\n"; + + try { + my $message = decode_json($resp->content); + + my $errorCode = $message->{"errorCode"}; + print "error code: ", $errorCode, "\n"; + my $errorMessage = $message->{"errorMessage"}; + print "error mesage: ", $errorMessage, "\n"; + } catch { + print $resp->message; + } + +} + +1; diff --git a/recipes/powershell/ClientBackup.ps1 b/recipes/powershell/ClientBackup.ps1 new file mode 100644 index 0000000..a3e9fdc --- /dev/null +++ b/recipes/powershell/ClientBackup.ps1 @@ -0,0 +1,338 @@ +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for launching a manual backup from a Windows client system +.DESCRIPTION +This script will query the master server for policy information and existing client backup images. If the latest full backup +is older than the frequency defined within the policy schedule a full backup will be launched; otherwise, an incremental will +be performed. +.EXAMPLE +.\ClientBackup.ps1 -p "ExampleClientBackup-Win" -k "AybRCz3UE_YOpCFD7_5mzQQfJsRXj_pN6WXLA7boX4EAuKD_kwBfXWQ5bFNWDiuJ" +#> + +<# +Requirements and comments for running this script +* Tested with PowerShell 5.1 but should work with PowerSell 3.0 or later +* Tested with NetBackup 8.3 +* NetBackup client software already installed, configured and tested +* A policy must be defined on the master server with the following details + * Policy type must be MS-Windows + * At least 2 schedules define with no backup windows + * one full + * one incremental + * Client name added to Clients tab +* Use command line parameters to specify the following parameters + * -policy (to reference above policy) + * -apikey (generated through NetBackup web UI) +* API key uesr must have following privileges assigned to it's role: + * Minimum specific privileges: + * Global -> NetBackup management -> NetBackup images -> View + * Global -> Protection -> Policies -> View + * Global -> Protection -> Policies -> Manual Backup +* PowerShell Execution Policy needs to be opened +#> + + +param ( + [string]$p = $(throw "Please specify the policy name using -p parameter."), + [string]$k = $(throw "Please specify the password using -k parameter."), + [switch]$v = $false, + [switch]$t = $false +) +$policy=$p +$apikey=$k +$verbose=$v +$testmode=$t + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Looking in the registry for NetBackup details +##################################################################### +$a = Get-ItemPropertyValue -path HKLM:\SOFTWARE\VERITAS\NetBackup\CurrentVersion\Config -name Server +$b = $a.Split(" ") +if ( $b -is [system.array] ) { + $nbmaster=$b[0] +} else { + $nbmaster=$b +} +$clientname = Get-ItemPropertyValue -path HKLM:\SOFTWARE\VERITAS\NetBackup\CurrentVersion\Config -name Client_Name + +if ( $verbose ) { + Write-Host "Looking at local NetBackup configuration for client name and master server" + Write-Host "nbmaster=$nbmaster" + Write-Host "clientname=$clientname" + Write-Host +} + +##################################################################### +# Global Variables +##################################################################### +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type = "application/vnd.netbackup+json;version=4.0" +$days2lookback = 30 +$fullname = "FULL" +$incrname = "INCR" +if ( $verbose ) { + Write-Host "Base URI = $basepath" + Write-Host "Looking back $days2lookback days for previous backups" + Write-Host +} + +##################################################################### +# Getting the policy details +##################################################################### +$uri = $basepath + "/config/policies/"+$policy +if ( $verbose ) { + Write-Host "Getting $policy policy details" + Write-Host "Using URI $uri" +} + +$headers = @{ + "Authorization" = $apikey + "X-NetBackup-Policy-Use-Generic-Schema" = "true" +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -Body $query_params ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 200) +{ + throw "Unable to get the list of Netbackup images!" +} + +# Converting JSON output into PowerShell object format +$content = (ConvertFrom-Json -InputObject $response) + +# Determining backup frequency for full backup and getting +# the full and incr schedule names +for ( $i=0; $i -lt $content.data.attributes.policy.schedules.count; $i++ ) { + if ( $content.data.attributes.policy.schedules[$i].schedulename -eq $fullname ) { + $fullfrequency = $content.data.attributes.policy.schedules[$i].frequencyseconds + $fullschedule = $content.data.attributes.policy.schedules[$i].schedulename + } + if ( $content.data.attributes.policy.schedules[$i].schedulename -like $incrname ) { + $incrfrequency = $content.data.attributes.policy.schedules[$i].frequencyseconds + $incrschedule = $content.data.attributes.policy.schedules[$i].schedulename + } +} + +if ( $verbose ) { + Write-Host "Incremental schedule $incrschedule frequency is $incrfrequency seconds" + Write-Host "Full schedule $fullschedule frequency is $fullfrequency seconds" + Write-Host +} + +##################################################################### +# Get NetBackup Images from last days2lookback (30 default) days for this client +##################################################################### +$uri = $basepath + "/catalog/images" +if ( $verbose ) { + Write-Host "Looking for most recent backup images to see what kind of backup to run" + Write-Host "Using URI $uri " +} + +$headers = @{ + "Authorization" = $apikey +} + +# Note that currentDate and lookbackDate are DateTime objects while +# backupTimeStart and backupTimeEnd are string date in ISO 8601 format +# using Zulu (Greenwich Mean Time) time: YYYY-MM-DDThh:mm:ssZ +# Date/Time format example: November 13, 1967 at 3:22:00 PM = 1967-11-13T15:22:00Z +# Getting current date +$a = Get-Date +$currentDate=$a.ToUniversalTime() +# Set starting date to 30 days from current date +$lookbackDate = (Get-Date).AddDays(-$days2lookback) +$backupTimeStart = (Get-Date -format s -date $lookbackDate) + "Z" + +$query_params = @{ + "page[limit]" = 50 # This changes the default page size to 50 + # The following filter variable adds a filter to only show for this client in past 30 days + "filter" = "clientName eq '$clientname' and backupTime ge $backupTimeStart" +} +if ( $verbose ) { + Write-Host "backupTimeStart = $backupTimeStart" +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -Body $query_params ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 200) +{ + throw "Unable to get the list of Netbackup images!" +} + +# Convert the JSON output into PowerShell object format +$content = (ConvertFrom-Json -InputObject $response) + +# Converting the JSON data for the image attributes into an array for looping through +$imageinfo = %{$content.data.attributes} + +# Setting values to validation variables +$schedulerun = "none" +$fulltime = 0 +$incrtime = 0 + +# Looping through all the images found for this client looking for most recent +# full and incr backup image. We just need to capture the first instance of either backup type +# Handling 3 scenarios of returned images counts: +# 1 image doesn't create an array of objects so need to process +# 2 or more images create array of objects to process in a loop +if ( $content.meta.pagination.count -eq 1 ) { + if ( $imageinfo.scheduleName -eq $fullname ) { + $fulltime = (Get-Date $imageinfo.backuptime) + } elseif ( $imageinfo.scheduleName -eq $incrname ) { + $incrtime= (Get-Date $imageinfo.backuptime) + } +} else { + for ( $i=0; $i -lt $content.meta.pagination.count; $i++ ) { + # Depending upon the schedule name, what to perform + if ( $imageinfo[$i].schedulename -eq $fullname ) { + $a = Get-Date $imageinfo[$i].backuptime + if ( $a -gt $fulltime ) { + $fulltime=$a + } + } elseif ( $imageinfo[$i].schedulename -eq $incrname ) { + $a = Get-Date $imageinfo[$i].backuptime + if ( $a -gt $incrtime ) { + $incrtime=$a + } + } + } +} + + +# Define the full and incr window by subtracting the schedule frequency from +# the current time. +$fullwindow=$currentDate.AddSeconds(-$fullfrequency) +$incrwindow=$currentDate.AddSeconds(-$incrfrequency) + +# Now, run through the logic to determine what kind of backup to run +if ( $fulltime -eq 0 ) { + # No recent backup images found for this client, run full backup + $schedulerun = $fullname +} elseif ( $fullwindow -ge $fulltime ) { + # Found a FULL backup older than current full window + $schedulerun = $fullname +} elseif ( $fulltime -ne 0 -AND $incrtime -eq 0 ) { + # Full backup found but less than window and no incremental + $schedulerun = $incrname +} elseif ( $incrwindow -ge $incrtime ) { + # Full backup less than window and incremental older than window + $schedulerun = $incrname +} else { + $schedulerun = "none" +} + +if ( $verbose ) { + Write-Host "schedulerun=$schedulerun" + Write-Host "fulltime=$fulltime" + Write-Host "incrtime=$incrtime" + Write-Host "fullwindow=$fullwindow" + Write-Host "incrwindow=$incrwindow" +} + +# If schedulerun is equal to none, then skip running anything +if ( $schedulerun -eq "none" ) { + Write-Host "Too soon to take a backup" + exit +} + +# Running this in testing mode which means we don't want to run a backup, +# just see what wwould be run +if ( $testmode ) { + exit +} + +##################################################################### +# Launch the backup now +##################################################################### +$uri = $basepath + "/admin/manual-backup" +if ( $verbose ) { + Write-Host "Launching the backup now" + Write-Host "Using URI $uri" +} + +$headers = @{ + "Authorization" = $apikey +} + +$backup_params = @{ + data = @{ + type = "backupRequest" + attributes = @{ + policyName = $policy + scheduleName = $schedulerun + clientName = $clientname + } + } +} + +$body = ConvertTo-Json -InputObject $backup_params + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body $body ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 202) +{ + # Backup job did not start successfully + "API StatusCode = "+$response.StatusCode + #Write-Host $response.errorResponse + #$content = (ConvertFrom-Json -InputObject $response) + #"NetBackup error code = "+$content.errorResponse.errorCode + #"NetBackup error message ="+$content.errorResponse.errorMessage + throw "Unable to start the backup for "+$clientname+" with schedule "+$schedulerun+" for policy "+$policy +} + +if ( $verbose ) { + Write-Host "Backup $schedulerun successfully started" +} diff --git a/recipes/powershell/README.md b/recipes/powershell/README.md index 4de13f2..5194dbc 100644 --- a/recipes/powershell/README.md +++ b/recipes/powershell/README.md @@ -1,17 +1,43 @@ -### NetBackup API Code Samples for PowerShell +### ClientBackup: initiate policy based backup from client -This directory contains code samples to invoke NetBackup REST APIs using PowerShell. +These scripts are designed to initiate a backup from the client using a specified policy and API key. The program logic in the script works like this: + +* Look at the local NetBackup configuration for the client name and the master server +* Using the /netbackup/config/policies API, get the details of the specified policy + * Look for the presence of an INCR and FULL schedule + * Get backup frequency of the INCR and FULL schedules +* Using /netbackup/catalog/images API, get the last 30 days of backup images for this client +* Compare the last backups to the schedule frequencies to determine what level (FULL or INCR) backup to run. +* Initiate the backup using the /netbackup/admin/manual-backup API #### Disclaimer -These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. +These scripts are only meant to be used as a reference. If you intend to use them in production, use them at your own risk. + +#### Pre-requisites + +* Tested with NetBackup 8.3 +* For Windows clients, tested with the following + * PowerShell version 5.1 + * Windows Server 2016 +* NetBackup client software already installed on client +* Policy defined on master server with following specifics + * Scheduled name Full defined as full backup type + * Schedule named Incr defined as incremental backup type + * Source clients added to Clients +* API user with key generated associated with role having these permissions + * Global -> NetBackup management -> NetBackup backup images -> View + * Global -> Protection -> Policies -> View + * Global -> Protection -> Policies -> Manual backup + +#### Executing ClientBackup.ps1 + +This PowerShell script is not signed so you may encounter errors trying to run this. You can use the PowerShell cmdlet [Set-Execution Policy](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7) to adjust your environment to allow running unsigned PowerShell scripts. -#### Executing the recipes in PowerShell +To execute, run the command like this: -Pre-requisites: -- NetBackup 8.1.2 or higher -- PowerShell 4.0 or higher +``` +ClientBackup.ps1 -p "POLICY" -k "APIKEY" [-v] +``` -Use the following commands to run the PowerShell samples. -- `.\create_policy_in_one_step.ps1 -nbmaster -username -password [-domainName ] [-domainType ]` -- `.\rbac_filtering_in_policy.ps1 -nbmaster -username -password [-domainName ] [-domainType ]` +Replace POLICY with the NetBackup policy to use and replace APIKEY with the API key generated through the NetBackup web UI. The optional -v option will provide additional information during the processing. Without the -v option, ClientBackup.ps1 will run silently. \ No newline at end of file diff --git a/recipes/powershell/admin/README.md b/recipes/powershell/admin/README.md new file mode 100755 index 0000000..545108a --- /dev/null +++ b/recipes/powershell/admin/README.md @@ -0,0 +1,17 @@ +### NetBackup API Code Samples for PowerShell + +This directory contains code samples to invoke NetBackup admin APIs using PowerShell. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Executing the recipes in PowerShell + +Pre-requisites: +- NetBackup 8.2 or higher +- PowerShell 4.0 or higher + +Use the following commands to run the PowerShell samples. +- `./get_processes.ps1 -MasterServer -UserName -Password -Client [-DomainName -DomainType ]` +- `./get_services.ps1 -MasterServer -UserName -Password -Client [-DomainName -DomainType ]` diff --git a/recipes/powershell/admin/get_processes.ps1 b/recipes/powershell/admin/get_processes.ps1 new file mode 100755 index 0000000..8849351 --- /dev/null +++ b/recipes/powershell/admin/get_processes.ps1 @@ -0,0 +1,178 @@ +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup processes REST API. +.DESCRIPTION +This script can be run using NetBackup 8.2 or higher version. +.EXAMPLE +./get_processes.ps1 -MasterServer -UserName -Password -Client [-DomainName -DomainType ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), + [string]$UserName = $(Throw "Please specify the user name using the -UserName parameter."), + [string]$Password = $(Throw "Please specify the password using the -Password parameter."), + [string]$Client = $(Throw "Please specify the client name using the -Client parameter."), + [string]$DomainName, + [string]$DomainType +) + + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" +$adminHostsUri = "admin/hosts/"; +$contentType = "application/vnd.netbackup+json;version=3.0" +$hostName = $Client +$testServiceName = "bpcd" + +###################################### +# Login to the NetBackup webservices +###################################### +Function Login() +{ + + $uri = $baseUri + "login" + + $body = @{ + userName=$UserName + password=$Password + } + if ($DomainName -ne "") { + $body.add("domainName", $DomainName) + } + if ($DomainType -ne "") { + $body.add("domainType", $DomainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices...`n" + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $content = (ConvertFrom-Json -InputObject $response) + return $content +} + +######################### +# Get a Host uuid +######################### +Function getUUID() +{ + $uri = $baseUri + "config/hosts?filter=" + $hostName + + + Write-Host "`nSending a GET request to get host UUID ..`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to get host UUID.`n" + } + + Write-Host "fetched UUID successfully.`n" + $content = (ConvertFrom-Json -InputObject $response) + return $content +} + +######################### +# Get a specific Processes +######################### +Function GetProcess() +{ + $uri = $baseUri + $adminHostsUri + $uuid + "/processes?filter=processName eq 'bpcd'" + + Write-Host "`nSending a GET request to read a specific processes on client $client...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to read processes on client $client.`n" + } + $response = (ConvertFrom-Json -InputObject $response) + $response.data.attributes | Format-Table -autosize +} + +################# +# Get Processes +################# +Function GetProcesses() +{ + $uri = $baseUri + $adminHostsUri + $uuid + "/processes" + + Write-Host "`nSending a GET request to read processes on client $client...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to read processes on client $client.`n" + } + $response = (ConvertFrom-Json -InputObject $response) + $response.data.attributes | Format-Table -autosize +} + + +Setup +$loginResponse = Login +$headers = @{"Authorization" = $loginResponse.token} +$uuidResponse = getUUID +$uuid = $uuidResponse.hosts[0].uuid +GetProcess +GetProcesses diff --git a/recipes/powershell/admin/get_services.ps1 b/recipes/powershell/admin/get_services.ps1 new file mode 100755 index 0000000..ddb0f23 --- /dev/null +++ b/recipes/powershell/admin/get_services.ps1 @@ -0,0 +1,197 @@ +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup Services REST APIs. +.DESCRIPTION +This script can be run using NetBackup 8.2 and higher. +We can get all the NB services or individual service along with their status. +.EXAMPLE +./get_services.ps1 -MasterServer -UserName -Password -Client [-DomainName -DomainType ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), + [string]$UserName = $(Throw "Please specify the user name using the -UserName parameter."), + [string]$Password = $(Throw "Please specify the password using the -Password parameter."), + [string]$Client = $(Throw "Please specify the client name using the -client parameter."), + [string]$DomainName, + [string]$DomainType +) + + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" +$servicesUri = "admin/hosts/"; +$contentType = "application/vnd.netbackup+json;version=3.0" +$hostName = $Client +$testServiceName = "bpcd" + +###################################### +# Login to the NetBackup webservices +###################################### +Function Login() +{ + + $uri = $baseUri + "login" + + $body = @{ + userName=$UserName + password=$Password + } + if ($DomainName -ne "") { + $body.add("domainName", $DomainName) + } + if ($DomainType -ne "") { + $body.add("domainType", $DomainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices...`n" + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $content = (ConvertFrom-Json -InputObject $response) + return $content +} +######################### +# Get a Host uuid +######################### +Function getUUID() +{ + $uri = $baseUri + "config/hosts?filter=" + $hostName + + + Write-Host "`nSending a GET request to get host UUID ..`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to get host UUID.`n" + } + + Write-Host "fetched UUID successfully.`n" + $content = (ConvertFrom-Json -InputObject $response) + return $content +} + +####################### +# List all nb services +####################### + +Function ListNbServices() +{ + $uri = $baseUri + $servicesUri + $uuid + "/services" + + Write-Host "`nSending a GET request to list all nb services on client $client...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to list Nb Services on client $client.`n" + } + + $content = (ConvertFrom-Json -InputObject $response) + + $content | ForEach-Object { + + $properties = + + @{Label = "Service Name"; Expression = { $_.id }}, + @{Label = "Status"; Expression = { $_.attributes.status }} + + $content.data | Format-Table -AutoSize -Property $properties + + } + +} + +######################### +# List a Specific Service +######################### + +Function ListNBService() +{ + $uri = $baseUri + $servicesUri + $uuid + "/services/" + $testServiceName + + Write-Host "`nSending a GET request to list specific Service on client $client ..`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to read service $testServiceName on client $client.`n" + } + $content = (ConvertFrom-Json -InputObject $response) + + $properties = + + @{Label = "Service Name"; Expression = { $_.id }}, + @{Label = "Status"; Expression = { $_.attributes.status }} + + $content.data | Format-Table -AutoSize -Property $properties +} + +Setup +$loginResponse = Login +$headers = @{"Authorization" = $loginResponse.token} +$uuidResponse = getUUID +$uuid = $uuidResponse.hosts[0].uuid +ListNBService +ListNbServices diff --git a/recipes/powershell/assets/README.md b/recipes/powershell/assets/README.md new file mode 100644 index 0000000..53ef8e9 --- /dev/null +++ b/recipes/powershell/assets/README.md @@ -0,0 +1,28 @@ +# NetBackup VMware Asset API Code Samples for PowerShell + +This directory contains PowerShell scripts demonstrating the use of NetBackup Asset Service APIs for creating and retrieving VMware assets. + +#### Disclaimer + +The samples are provided only for reference and not meant for production use. + +#### Executing the recipes in PowerShell + +##### Prerequisites: + +- NetBackup 8.3 or higher +- PowerShell 4.0 or higher + +##### Script Details + +- get_vmware_assets script uses the NetBackup Asset Service API to get the VMware workload assets (filtered by the given filter if specified). It prints the details such as asset display name, instance Id, vCenter and the plan names that the asset is protected by. +Note: assetsFilter (should be in OData format; refer to the NetBackup API documentation) can be used to filter the assets returned. It is optional; if not specified the script will print all the VM assets. Redirect the script output to a file to avoid printing the details on terminal. + +- create_vmware_asset_group script creates a VMware asset group using sample data provided inside the script. Redirect the script output to a file to +avoid printing the details on terminal. + +##### Running the Scripts + +Use the following commands to run the PowerShell sample: +- .\get_vmware_assets.ps1 -MasterServer -username -password [-domainName ] [-domainType ] [-assetType ] [-assetsFilter ] +- .\create_vmware_asset_group.ps1 -MasterServer -username -password [-domainName ] [-domainType ] diff --git a/recipes/powershell/assets/create_vmware_asset_group.ps1 b/recipes/powershell/assets/create_vmware_asset_group.ps1 new file mode 100644 index 0000000..46872f2 --- /dev/null +++ b/recipes/powershell/assets/create_vmware_asset_group.ps1 @@ -0,0 +1,169 @@ +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup APIs for creating VMware asset group +.DESCRIPTION +This script can be run using NetBackup 8.3 and higher. +It creates a VMware asset group +.EXAMPLE +./create_vmware_asset_group.ps1 -MasterServer -username -password [-domainName -domainType ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), + [string]$username = $(Throw "Please specify the user name using the -username parameter."), + [string]$password = $(Throw "Please specify the password using the -password parameter."), + [string]$domainName, + [string]$domainType +) + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" +$assetServiceUri = "asset-service/queries"; +$contentType = "application/vnd.netbackup+json;version=4.0" + + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +###################################### +# Login to the NetBackup webservices +###################################### + +Function Login() +{ + $uri = $baseUri + "login" + + $body = @{ + userName=$username + password=$password + } + if ($domainName -ne "") { + $body.add("domainName", $domainName) + } + if ($domainType -ne "") { + $body.add("domainType", $domainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $response = (ConvertFrom-Json -InputObject $response) + return $response +} + + +################################################# +# Create Asset Group +################################################# +Function createAssetGroup() +{ + $uri = $baseUri + $assetServiceUri + + $assetGroupDataJson = '{ + "data": { + "type": "query", + "attributes": { + "queryName": "create-or-update-assets", + "workloads": ["vmware"], + "parameters": { + "objectList": [ + { + "correlationId": "corr-groupvcfdf", + "type": "vmwareGroupAsset", + "assetGroup": { + "description": "sampleDescription", + "assetType": "vmGroup", + "filterConstraint": "sampleMachine", + "oDataQueryFilter": "true", + "commonAssetAttributes": { + "displayName": "sampleGroup249", + "workloadType": "vmware", + "protectionCapabilities": { + "isProtectable": "YES", + "isProtectableReason": "sampleReason", + "isRecoverable": "NO", + "isRecoverableReason": "sampleReason" + }, + "detection": { + "detectionMethod": "MANUAL" + } + } + } + } + ] + } + } + } + }' + + Write-Host "Creating Asset Group.`n" + + $response_create_asset_group = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body ($assetGroupDataJson) ` + -ContentType $contentType ` + -Headers $headers + + if ($response_create_asset_group.StatusCode -ne 201) + { + throw "Unable to create asset group." + } + + Write-Host "asset group created successfully.`n" + echo $response_create_asset_group + Write-Host $response_create_asset_group + + $response_create_stu = (ConvertFrom-Json -InputObject $response_create_asset_group) +} + +Setup +$loginResponse = Login +$headers = @{"Authorization" = $loginResponse.token} +createAssetGroup diff --git a/recipes/powershell/assets/get_vmware_assets.ps1 b/recipes/powershell/assets/get_vmware_assets.ps1 new file mode 100644 index 0000000..70b40f2 --- /dev/null +++ b/recipes/powershell/assets/get_vmware_assets.ps1 @@ -0,0 +1,181 @@ +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup APIs for retieving VMware plugin information. +.DESCRIPTION +This script can be run using NetBackup 8.3 and higher. +It retrieves VMware asset data +.EXAMPLE +./get_VMware_Asset_Data.ps1 -MasterServer -username -password [-domainName -domainType ][-assetType ][-assetsFilter ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), + [string]$username = $(Throw "Please specify the user name using the -username parameter."), + [string]$password = $(Throw "Please specify the password using the -password parameter."), + [string]$domainName, + [string]$domainType, + [string]$assetType, + [string]$assetsFilter +) + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" +$assetServiceUri = "asset-service/workloads/vmware/assets?"; +$contentType = "application/vnd.netbackup+json;version=4.0" + + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +###################################### +# Login to the NetBackup webservices +###################################### + +Function Login() +{ + $uri = $baseUri + "login" + + $body = @{ + userName=$username + password=$password + } + if ($domainName -ne "") { + $body.add("domainName", $domainName) + } + if ($domainType -ne "") { + $body.add("domainType", $domainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $response = (ConvertFrom-Json -InputObject $response) + return $response +} + + +################################################# +# GET Assets +################################################# +Function getAssets() +{ + $uri = $baseUri + $assetServiceUri + + $default_sort = "sort=commonAssetAttributes.displayName" + + if($assetType -eq "vm"){ + $assetTypeFilter = "filter=assetType eq 'vm'" + } + elseif($assetType -eq "vmGroup"){ + $assetTypeFilter = "filter=assetType eq 'vmGroup'" + } + + if(![string]::IsNullOrEmpty($assetsFilter)){ + if([string]::IsNullOrEmpty($assetTypeFilter)){ + $assetTypeFilter = "filter=" + $assetsFilter + } + else{ + $assetTypeFilter = $assetTypeFilter + " and " + $assetsFilter + } + } + + $offset = 0 + $next = $true + + while ($next){ + $uri = $baseUri + $assetServiceUri + $assetTypeFilter + "&" + $default_sort + "&page[offset]=$offset" + + Write-Host "`nSending a GET request to list all Assets...`n" + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to get VMware assets.`n" + } + + $api_response = (ConvertFrom-Json -InputObject $response) + + if($assetType -eq "vmGroup"){ + $vmGroup_data = + @{Label = "DisplayName"; Expression = { $_.attributes.commonAssetAttributes.displayName}}, + @{Label = "filterConstraint"; Expression = { $_.attributes.filterConstraint }}, + @{Label = "oDataQueryFilter"; Expression = { $_.attributes.oDataQueryFilter }}, + @{Label = "Asset Protection Plans"; Expression = { $_.attributes.commonAssetAttributes.activeProtection.protectionDetailsList }} + + $api_response.data | Format-Table -AutoSize -Property $vmGroup_data + } + else{ + $vm_data = + @{Label = "DisplayName"; Expression = { $_.attributes.commonAssetAttributes.displayName}}, + @{Label = "InstanceUUID"; Expression = { $_.attributes.instanceUuid }}, + @{Label = "vCenter"; Expression = { $_.attributes.vCenter }}, + @{Label = "Asset Protection Plans"; Expression = { $_.attributes.commonAssetAttributes.activeProtection.protectionDetailsList }} + + $api_response.data | Format-Table -AutoSize -Property $vm_data + + } + + $offset = $offset + $api_response.meta.pagination.limit + + if($api_response.meta.pagination.hasNext -eq $false){ + $next = $false + } + + } +} + +Setup +$loginResponse = Login +$headers = @{"Authorization" = $loginResponse.token} +getAssets diff --git a/recipes/powershell/config/README.md b/recipes/powershell/config/README.md new file mode 100644 index 0000000..8ec6979 --- /dev/null +++ b/recipes/powershell/config/README.md @@ -0,0 +1,16 @@ +### NetBackup API Code Samples for PowerShell + +This directory contains code samples to invoke NetBackup config APIs using PowerShell. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Executing the recipes in PowerShell + +Pre-requisites: +- NetBackup 8.2 or higher +- PowerShell 4.0 or higher + +Use the following commands to run the PowerShell samples. +- `./configManagement_curd_operations.ps1 -MasterServer -UserName -Password -Client [-DomainName -DomainType ]` diff --git a/recipes/powershell/config/configManagement_curd_operations.ps1 b/recipes/powershell/config/configManagement_curd_operations.ps1 new file mode 100755 index 0000000..1d36fb4 --- /dev/null +++ b/recipes/powershell/config/configManagement_curd_operations.ps1 @@ -0,0 +1,209 @@ +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup Hosts Configuration APIs. +.DESCRIPTION +The script can be run using NetBackup 8.2 or higher. +It updates the exclude list configuration on the specified client. The exclude list is specified within the script below. +.EXAMPLE +./configManagement_curd_operations.ps1 -MasterServer -UserName -Password -Client [-DomainName -DomainType ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), + [string]$UserName = $(Throw "Please specify the user name using the -UserName parameter."), + [string]$Password = $(Throw "Please specify the password using the -Password parameter."), + [string]$Client = $(Throw "Please specify the client name using the -client parameter."), + [string]$DomainName, + [string]$DomainType +) + + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" +$HostsUri = "config/hosts/" +$contentType = "application/vnd.netbackup+json;version=3.0" +$hostName = $client +$Configurations = "/configurations/exclude" + +###################################### +# Login to the NetBackup webservices +###################################### +Function Login() +{ + + $uri = $baseUri + "login" + + $body = @{ + userName=$UserName + password=$Password + } + if ($DomainName -ne "") { + $body.add("domainName", $DomainName) + } + if ($DomainType -ne "") { + $body.add("domainType", $DomainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices...`n" + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $content = (ConvertFrom-Json -InputObject $response) + return $content +} +######################### +# Get a Host uuid +######################### +Function getUUID() +{ + $uri = $baseUri + "config/hosts?filter=" + $hostName + + + Write-Host "`nSending a GET request to get host UUID ..`n" + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to get host UUID.`n" + } + + Write-Host "fetched UUID successfully.`n" + $content = (ConvertFrom-Json -InputObject $response) + return $content +} + +############################# +#Get a Exclude config Setting +############################## + +Function getConfigSetting() +{ + $uri = $baseUri + $HostsUri + $uuid + $configurations + + Write-Host "`nSending a GET request to get a Exclude List...`n" + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable get the Exclude List.`n" + } + + $content = (ConvertFrom-Json -InputObject $response) + + Write-Host "`nExclude List for the given host...`n" + + foreach ($value in $content.data.attributes.value) {$value} + +} + +######################### +# Update the Exclude List +######################### + +Function updateConfigSetting() +{ + $uri = $baseUri + $HostsUri + $uuid + $configurations + + $value = @("C:\\Program Files\\Veritas\\NetBackup\\bin\\*.lock", + "C:\\Program Files\\Veritas\\NetBackup\\bin\\bprd.d\\*.lock", + "C:\\Program Files\\Veritas\\NetBackup\\bin\\bpsched.d\\*.lock", + "C:\\Program Files\\Veritas\\Volmgr\\misc\\*", + "C:\\Program Files\\Veritas\\NetBackupDB\\data\\*", + "C:\\test0", + "C:\\test1" + ) + + $data = @{ + type="hostConfiguration" + id="exclude" + attributes=@{value=$value} +} + + $body = @{data=$data} | ConvertTo-Json -Depth 9 + + Write-Host "`nSending a Update request to update a Exclude List...`n" + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method PUT ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to update the Exclude List.`n" + } + + + Write-Host "`nSuccessfully Updated the Exclude List...`n" + +} + +Setup +$loginResponse = Login +$headers = @{"Authorization" = $loginResponse.token} +$uuidResponse = getUUID +$uuid = $uuidResponse.hosts[0].uuid +getConfigSetting +updateConfigSetting +Write-Host "`nNow get the updated Exclude List...`n" +getConfigSetting diff --git a/recipes/powershell/New-Policy-StepByStep.ps1 b/recipes/powershell/policies/New-Policy-StepByStep.ps1 similarity index 95% rename from recipes/powershell/New-Policy-StepByStep.ps1 rename to recipes/powershell/policies/New-Policy-StepByStep.ps1 index 4575458..f66d10c 100755 --- a/recipes/powershell/New-Policy-StepByStep.ps1 +++ b/recipes/powershell/policies/New-Policy-StepByStep.ps1 @@ -1,426 +1,426 @@ -<# -.SYNOPSIS -This sample script demonstrates the use of NetBackup Policy REST APIs. -.DESCRIPTION -This script can be run using NetBackup 8.1.2 and higher. -It creates a policy with the default values for policy type specific attributes, adds a client, schedule, and backup selection to it, then deletes the client, schedule and finally deletes the policy. -.EXAMPLE -./New-Policy-StepByStep.ps1 -MasterServer "nb-master.example.com" -UserName "administrator" -Password "password" -DomainName "domain name" -#> - -#Requires -Version 4.0 - -Param ( - [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), - [string]$UserName = $(Throw "Please specify the user name using the -UserName parameter."), - [string]$Password = $(Throw "Please specify the password using the -Password parameter."), - [string]$DomainName, - [string]$DomainType -) - -#################### -# Global Variables -#################### - -$port = 1556 -$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" -$policiesUri = "config/policies/"; -$contentType = "application/vnd.netbackup+json;version=2.0" -$testPolicyName = "vmware_test_policy" -$testClientName = "MEDIA_SERVER" -$testScheduleName = "vmware_test_schedule" - -############################################################### -# Setup to allow self-signed certificates and enable TLS v1.2 -############################################################### -Function Setup() -{ - # Allow self-signed certificates - if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') - { - Add-Type -TypeDefinition @" - using System.Net; - using System.Security.Cryptography.X509Certificates; - public class TrustAllCertsPolicy : ICertificatePolicy { - public bool CheckValidationResult( - ServicePoint srvPoint, X509Certificate certificate, - WebRequest request, int certificateProblem) { - return true; - } - } -"@ - [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy - } - - # Force TLS v1.2 - try { - if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - } - } - catch { - Write-Host "`n"$_.Exception.InnerException.Message - } -} - -###################################### -# Login to the NetBackup webservices -###################################### - -Function Login() -{ - $uri = $baseUri + "login" - - $body = @{ - userName=$UserName - password=$Password - } - if ($DomainName -ne "") { - $body.add("domainName", $DomainName) - } - if ($DomainType -ne "") { - $body.add("domainType", $DomainType) - } - Write-Host "`nSending a POST request to login to the NetBackup webservices..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body (ConvertTo-Json -InputObject $body) ` - -ContentType $contentType - - if ($response.StatusCode -ne 201) - { - throw "Unable to connect to the NetBackup Master Server" - } - - Write-Host "Login successful.`n" - $response = (ConvertFrom-Json -InputObject $response) - return $response -} - - -################################################# -# Create a policy with default attribute values -################################################# -Function CreatePolicyWithDefaults() -{ - $uri = $baseUri + $policiesUri - - $policy = @{ - policyName=$testPolicyName - policyType="VMware" - policyAttributes=@{} - clients=@() - schedules=@() - backupSelections=@{selections=@()} - } - - $data = @{ - type="policy" - id=$testPolicyName - attributes=@{policy=$policy} - } - - $body = @{data=$data} | ConvertTo-Json -Depth 5 - - Write-Host "`nSending a POST request to create $testPolicyName with defaults..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to create policy $testPolicyName." - } - - Write-Host "$testPolicyName created successfully.`n" - $response = (ConvertFrom-Json -InputObject $response) -} - -##################### -# List all policies -##################### -Function ListPolicies() -{ - $uri = $baseUri + $policiesUri - - Write-Host "`nSending a GET request to list all policies...`n" - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method GET ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 200) - { - throw "Unable to list policies.`n" - } - - Write-Host $response -} - -################# -# Read a policy -################# -Function ReadPolicy() -{ - $uri = $baseUri + $policiesUri + $testPolicyName - - Write-Host "`nSending a GET request to read policy $testPolicyName...`n" - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method GET ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 200) - { - throw "Unable to read policy $testPolicyName.`n" - } - - Write-Host $response -} - -################### -# Delete a policy -################### -Function DeletePolicy() -{ - $uri = $baseUri + $policiesUri + $testPolicyName - - Write-Host "`nSending a DELETE request to delete policy $testPolicyName..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method DELETE ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to delete policy $testPolicyName.`n" - } - - Write-Host "$testPolicyName deleted successfully.`n" -} - -############################ -# Add a client to a policy -############################ -Function AddClient() -{ - $uri = $baseUri + $policiesUri + $testPolicyName + "/clients/" + $testClientName - - $data = @{ - type="client" - attributes=@{ - hardware="VMware" - hostName="MEDIA_SERVER" - OS="VMware" - } - } - - $body = @{data=$data} | ConvertTo-Json -Depth 3 - - Write-Host "`nSending a PUT request to add client $testClientName to policy $testPolicyName..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method PUT ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 201) - { - throw "Unable to add client $testClientName to policy $testPolicyName.`n" - } - - Write-Host "$testClientName added to $testPolicyName successfully.`n" -} - -################################# -# Delete a client from a policy -################################# -Function DeleteClient() -{ - $uri = $baseUri + $policiesUri + $testPolicyName + "/clients/" + $testClientName - - Write-Host "`nSending a DELETE request to delete client $testClientName from policy $testPolicyName..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method DELETE ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to delete client $testClientName.`n" - } - - Write-Host "$testClientName deleted successfully.`n" -} - -###################################### -# Add a backup selection to a policy -###################################### -Function AddBackupSelection() -{ - $uri = $baseUri + $policiesUri + $testPolicyName + "/backupselections" - - $data = @{ - type="backupSelection" - attributes=@{ - selections=@("vmware:/?filter=Displayname Contains 'rsv' OR Displayname Contains 'mtv'") - } - } - - $body = @{data=$data} | ConvertTo-Json -Depth 3 - - Write-Host "`nSending a PUT request to add backupselection to policy $testPolicyName..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method PUT ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to add backupselection to policy $testPolicyName.`n" - } - - Write-Host "backupselection added to $testPolicyName successfully.`n" -} - -############################ -# Add a schedule to policy -############################ -Function AddSchedule() -{ - $uri = $baseUri + $policiesUri + $testPolicyName + "/schedules/" + $testScheduleName - - $data = @{ - type="schedule" - id=$testScheduleName - attributes=@{ - acceleratorForcedRescan=$false - backupCopies=@{ - priority=9999 - copies=@(@{ - mediaOwner="owner1" - storage=$null - retentionPeriod=@{ - value=9 - unit="WEEKS" - } - volumePool="NetBackup" - failStrategy="Continue" - } - ) - } - backupType="Full Backup" - excludeDates=@{ - lastDayOfMonth=$true - recurringDaysOfWeek=@("4:6", "2:5") - recurringDaysOfMonth=@(10) - specificDates=@("2000-1-1", "2016-2-30") - } - frequencySeconds=4800 - includeDates=@{ - lastDayOfMonth=$true - recurringDaysOfWeek=@("2:3", "3:4") - recurringDaysOfMonth=@(10,13) - specificDates=@("2016-12-31") - } - mediaMultiplexing=2 - retriesAllowedAfterRunDay=$true - scheduleType="Calendar" - snapshotOnly=$false - startWindow=@(@{dayOfWeek=1 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=2 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=3 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=4 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=5 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=6 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=7 - startSeconds=14600 - durationSeconds=24600} - ) - syntheticBackup=$false - storageIsSLP=$false - } - } - - $body = @{data=$data} | ConvertTo-Json -Depth 6 - - Write-Host "`nSending a PUT request to add schedule $testScheduleName to policy $testPolicyName..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method PUT ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 201) - { - throw "Unable to add schedule $testScheduleName to policy $testPolicyName.`n" - } - - Write-Host "schedule $testScheduleName added to $testPolicyName successfully.`n" -} - -################################### -# Delete a schedule from a policy -################################### -Function DeleteSchedule() -{ - $uri = $baseUri + $policiesUri + $testPolicyName + "/schedules/" + $testScheduleName - - Write-Host "`nSending a DELETE request to delete schedule $testScheduleName from policy $testPolicyName..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method DELETE ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to delete schedule $testScheduleName.`n" - } - - Write-Host "$testScheduleName deleted successfully.`n" -} - -Setup -$loginResponse = Login -$headers = @{"Authorization" = $loginResponse.token} -CreatePolicyWithDefaults -ListPolicies -ReadPolicy -AddClient -AddBackupSelection -AddSchedule -ReadPolicy -DeleteClient -DeleteSchedule -ReadPolicy -DeletePolicy -ListPolicies +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup Policy REST APIs. +.DESCRIPTION +This script can be run using NetBackup 8.1.2 and higher. +It creates a policy with the default values for policy type specific attributes, adds a client, schedule, and backup selection to it, then deletes the client, schedule and finally deletes the policy. +.EXAMPLE +./New-Policy-StepByStep.ps1 -MasterServer -UserName -Password [-DomainName -DomainType ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), + [string]$UserName = $(Throw "Please specify the user name using the -UserName parameter."), + [string]$Password = $(Throw "Please specify the password using the -Password parameter."), + [string]$DomainName, + [string]$DomainType +) + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" +$policiesUri = "config/policies/"; +$contentType = "application/vnd.netbackup+json;version=2.0" +$testPolicyName = "vmware_test_policy" +$testClientName = "MEDIA_SERVER" +$testScheduleName = "vmware_test_schedule" + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +###################################### +# Login to the NetBackup webservices +###################################### + +Function Login() +{ + $uri = $baseUri + "login" + + $body = @{ + userName=$UserName + password=$Password + } + if ($DomainName -ne "") { + $body.add("domainName", $DomainName) + } + if ($DomainType -ne "") { + $body.add("domainType", $DomainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $response = (ConvertFrom-Json -InputObject $response) + return $response +} + + +################################################# +# Create a policy with default attribute values +################################################# +Function CreatePolicyWithDefaults() +{ + $uri = $baseUri + $policiesUri + + $policy = @{ + policyName=$testPolicyName + policyType="VMware" + policyAttributes=@{} + clients=@() + schedules=@() + backupSelections=@{selections=@()} + } + + $data = @{ + type="policy" + id=$testPolicyName + attributes=@{policy=$policy} + } + + $body = @{data=$data} | ConvertTo-Json -Depth 5 + + Write-Host "`nSending a POST request to create $testPolicyName with defaults..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to create policy $testPolicyName." + } + + Write-Host "$testPolicyName created successfully.`n" + $response = (ConvertFrom-Json -InputObject $response) +} + +##################### +# List all policies +##################### +Function ListPolicies() +{ + $uri = $baseUri + $policiesUri + + Write-Host "`nSending a GET request to list all policies...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to list policies.`n" + } + + Write-Host $response +} + +################# +# Read a policy +################# +Function ReadPolicy() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + + Write-Host "`nSending a GET request to read policy $testPolicyName...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to read policy $testPolicyName.`n" + } + + Write-Host $response +} + +################### +# Delete a policy +################### +Function DeletePolicy() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + + Write-Host "`nSending a DELETE request to delete policy $testPolicyName..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to delete policy $testPolicyName.`n" + } + + Write-Host "$testPolicyName deleted successfully.`n" +} + +############################ +# Add a client to a policy +############################ +Function AddClient() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + "/clients/" + $testClientName + + $data = @{ + type="client" + attributes=@{ + hardware="VMware" + hostName="MEDIA_SERVER" + OS="VMware" + } + } + + $body = @{data=$data} | ConvertTo-Json -Depth 3 + + Write-Host "`nSending a PUT request to add client $testClientName to policy $testPolicyName..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method PUT ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 201) + { + throw "Unable to add client $testClientName to policy $testPolicyName.`n" + } + + Write-Host "$testClientName added to $testPolicyName successfully.`n" +} + +################################# +# Delete a client from a policy +################################# +Function DeleteClient() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + "/clients/" + $testClientName + + Write-Host "`nSending a DELETE request to delete client $testClientName from policy $testPolicyName..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to delete client $testClientName.`n" + } + + Write-Host "$testClientName deleted successfully.`n" +} + +###################################### +# Add a backup selection to a policy +###################################### +Function AddBackupSelection() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + "/backupselections" + + $data = @{ + type="backupSelection" + attributes=@{ + selections=@("vmware:/?filter=Displayname Contains 'rsv' OR Displayname Contains 'mtv'") + } + } + + $body = @{data=$data} | ConvertTo-Json -Depth 3 + + Write-Host "`nSending a PUT request to add backupselection to policy $testPolicyName..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method PUT ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to add backupselection to policy $testPolicyName.`n" + } + + Write-Host "backupselection added to $testPolicyName successfully.`n" +} + +############################ +# Add a schedule to policy +############################ +Function AddSchedule() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + "/schedules/" + $testScheduleName + + $data = @{ + type="schedule" + id=$testScheduleName + attributes=@{ + acceleratorForcedRescan=$false + backupCopies=@{ + priority=9999 + copies=@(@{ + mediaOwner="owner1" + storage=$null + retentionPeriod=@{ + value=9 + unit="WEEKS" + } + volumePool="NetBackup" + failStrategy="Continue" + } + ) + } + backupType="Full Backup" + excludeDates=@{ + lastDayOfMonth=$true + recurringDaysOfWeek=@("4:6", "2:5") + recurringDaysOfMonth=@(10) + specificDates=@("2000-1-1", "2016-2-30") + } + frequencySeconds=4800 + includeDates=@{ + lastDayOfMonth=$true + recurringDaysOfWeek=@("2:3", "3:4") + recurringDaysOfMonth=@(10,13) + specificDates=@("2016-12-31") + } + mediaMultiplexing=2 + retriesAllowedAfterRunDay=$true + scheduleType="Calendar" + snapshotOnly=$false + startWindow=@(@{dayOfWeek=1 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=2 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=3 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=4 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=5 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=6 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=7 + startSeconds=14600 + durationSeconds=24600} + ) + syntheticBackup=$false + storageIsSLP=$false + } + } + + $body = @{data=$data} | ConvertTo-Json -Depth 6 + + Write-Host "`nSending a PUT request to add schedule $testScheduleName to policy $testPolicyName..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method PUT ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 201) + { + throw "Unable to add schedule $testScheduleName to policy $testPolicyName.`n" + } + + Write-Host "schedule $testScheduleName added to $testPolicyName successfully.`n" +} + +################################### +# Delete a schedule from a policy +################################### +Function DeleteSchedule() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + "/schedules/" + $testScheduleName + + Write-Host "`nSending a DELETE request to delete schedule $testScheduleName from policy $testPolicyName..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to delete schedule $testScheduleName.`n" + } + + Write-Host "$testScheduleName deleted successfully.`n" +} + +Setup +$loginResponse = Login +$headers = @{"Authorization" = $loginResponse.token} +CreatePolicyWithDefaults +ListPolicies +ReadPolicy +AddClient +AddBackupSelection +AddSchedule +ReadPolicy +DeleteClient +DeleteSchedule +ReadPolicy +DeletePolicy +ListPolicies diff --git a/recipes/powershell/policies/README.md b/recipes/powershell/policies/README.md new file mode 100755 index 0000000..4fbb46a --- /dev/null +++ b/recipes/powershell/policies/README.md @@ -0,0 +1,23 @@ +### NetBackup API Code Samples for PowerShell + +This directory contains code samples to invoke NetBackup Policy APIs using PowerShell. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Executing the recipes in PowerShell + +Pre-requisites: +- NetBackup 8.1.2 or higher + + - **NOTE:** The following scripts configure access control using the old RBAC design and will only work on NetBackup + release 8.1.2 or 8.2. + - recipes/perl/policies/rbac_filtering_in_policy.ps1 + +- PowerShell 4.0 or higher + +Use the following commands to run the PowerShell samples. +- `.\create_policy_in_one_step.ps1 -MasterServer -username -password [-domainName ] [-domainType ]` +- `.\rbac_filtering_in_policy.ps1 -MasterServer -username -password [-domainName ] [-domainType ]` +- `./New-Policy-StepByStep.ps1 -MasterServer -UserName -Password [-DomainName -DomainType ]` diff --git a/recipes/powershell/create_policy_in_one_step.ps1 b/recipes/powershell/policies/create_policy_in_one_step.ps1 similarity index 93% rename from recipes/powershell/create_policy_in_one_step.ps1 rename to recipes/powershell/policies/create_policy_in_one_step.ps1 index 0be4452..b4038cb 100755 --- a/recipes/powershell/create_policy_in_one_step.ps1 +++ b/recipes/powershell/policies/create_policy_in_one_step.ps1 @@ -1,288 +1,288 @@ -<# -.SYNOPSIS -This sample script demonstrates the use of NetBackup Policy REST APIs. -.DESCRIPTION -This script can be run using NetBackup 8.1.2 and higher. -It creates a policy with the default values for policy type specific attributes, adds a client, schedule, and backup selection to it in one step at the time of creating policy -.EXAMPLE -./create_policy_in_one_step.ps1 -nbmaster -username -password [-domainName -domainType ] -#> - -#Requires -Version 4.0 - -Param ( - [string]$nbmaster = $(Throw "Please specify the name of the NetBackup Master Server using the -nbmaster parameter."), - [string]$username = $(Throw "Please specify the user name using the -username parameter."), - [string]$password = $(Throw "Please specify the password using the -password parameter."), - [string]$domainName, - [string]$domainType -) - -#################### -# Global Variables -#################### - -$port = 1556 -$baseUri = "https://" + $nbmaster + ":" + $port + "/netbackup/" -$policiesUri = "config/policies/"; -$contentType = "application/vnd.netbackup+json;version=2.0" -$testPolicyName = "vmware_test_policy" -$testClientName = "MEDIA_SERVER" -$testScheduleName = "vmware_test_schedule" - -############################################################### -# Setup to allow self-signed certificates and enable TLS v1.2 -############################################################### -Function Setup() -{ - # Allow self-signed certificates - if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') - { - Add-Type -TypeDefinition @" - using System.Net; - using System.Security.Cryptography.X509Certificates; - public class TrustAllCertsPolicy : ICertificatePolicy { - public bool CheckValidationResult( - ServicePoint srvPoint, X509Certificate certificate, - WebRequest request, int certificateProblem) { - return true; - } - } -"@ - [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy - } - - # Force TLS v1.2 - try { - if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - } - } - catch { - Write-Host "`n"$_.Exception.InnerException.Message - } -} - -###################################### -# Login to the NetBackup webservices -###################################### - -Function Login() -{ - $uri = $baseUri + "login" - - $body = @{ - userName=$username - password=$password - } - if ($domainName -ne "") { - $body.add("domainName", $domainName) - } - if ($domainType -ne "") { - $body.add("domainType", $domainType) - } - Write-Host "`nSending a POST request to login to the NetBackup webservices..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body (ConvertTo-Json -InputObject $body) ` - -ContentType $contentType - - if ($response.StatusCode -ne 201) - { - throw "Unable to connect to the NetBackup Master Server" - } - - Write-Host "Login successful.`n" - $response = (ConvertFrom-Json -InputObject $response) - return $response -} - - -################################################# -# Create a policy with default attribute values, but -# custom schedules, backupselections and clients -################################################# -Function CreatePolicy() -{ - $uri = $baseUri + $policiesUri - - $clients = @{ - hardware="VMware" - hostName="MEDIA_SERVER" - OS="VMware" - } - - $backupSelections = "vmware:/?filter=Displayname Contains 'rsv' OR Displayname Contains 'mtv'" - - $schedules = @{ - scheduleName="sched-9-weeks" - acceleratorForcedRescan=$false - backupCopies=@{ - priority=9999 - copies=@(@{ - mediaOwner="owner1" - storage=$null - retentionPeriod=@{ - value=9 - unit="WEEKS" - } - volumePool="NetBackup" - failStrategy="Continue" - } - ) - } - backupType="Full Backup" - excludeDates=@{ - lastDayOfMonth=$true - recurringDaysOfWeek=@("4:6", "2:5") - recurringDaysOfMonth=@(10) - specificDates=@("2000-1-1", "2016-2-30") - } - frequencySeconds=4800 - includeDates=@{ - lastDayOfMonth=$true - recurringDaysOfWeek=@("2:3", "3:4") - recurringDaysOfMonth=@(10,13) - specificDates=@("2016-12-31") - } - mediaMultiplexing=2 - retriesAllowedAfterRunDay=$true - scheduleType="Calendar" - snapshotOnly=$false - startWindow=@(@{dayOfWeek=1 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=2 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=3 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=4 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=5 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=6 - startSeconds=14600 - durationSeconds=24600}, - @{dayOfWeek=7 - startSeconds=14600 - durationSeconds=24600} - ) - syntheticBackup=$false - storageIsSLP=$false - } - - $policy = @{ - policyName=$testPolicyName - policyType="VMware" - policyAttributes=@{} - clients=@($clients) - schedules=@($schedules) - backupSelections=@{selections=@($backupSelections)} - } - - $data = @{ - type="policy" - id=$testPolicyName - attributes=@{policy=$policy} - } - - $body = @{data=$data} | ConvertTo-Json -Depth 9 - - Write-Host "`nSending a POST request to create $testPolicyName..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to create policy $testPolicyName." - } - - Write-Host "$testPolicyName created successfully.`n" - $response = (ConvertFrom-Json -InputObject $response) -} - -##################### -# List all policies -##################### -Function ListPolicies() -{ - $uri = $baseUri + $policiesUri - - Write-Host "`nSending a GET request to list all policies...`n" - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method GET ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 200) - { - throw "Unable to list policies.`n" - } - - Write-Host $response -} - -################# -# Read a policy -################# -Function ReadPolicy() -{ - $uri = $baseUri + $policiesUri + $testPolicyName - - Write-Host "`nSending a GET request to read policy $testPolicyName...`n" - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method GET ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 200) - { - throw "Unable to read policy $testPolicyName.`n" - } - - Write-Host $response -} - -################### -# Delete a policy -################### -Function DeletePolicy() -{ - $uri = $baseUri + $policiesUri + $testPolicyName - - Write-Host "`nSending a DELETE request to delete policy $testPolicyName..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method DELETE ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to delete policy $testPolicyName.`n" - } - - Write-Host "$testPolicyName deleted successfully.`n" -} - -Setup -$loginResponse = Login -$headers = @{"Authorization" = $loginResponse.token} -CreatePolicy -ListPolicies -ReadPolicy -DeletePolicy -ListPolicies +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup Policy REST APIs. +.DESCRIPTION +This script can be run using NetBackup 8.1.2 and higher. +It creates a policy with the default values for policy type specific attributes, adds a client, schedule, and backup selection to it in one step at the time of creating policy +.EXAMPLE +./create_policy_in_one_step.ps1 -MasterServer -username -password [-domainName -domainType ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), + [string]$username = $(Throw "Please specify the user name using the -username parameter."), + [string]$password = $(Throw "Please specify the password using the -password parameter."), + [string]$domainName, + [string]$domainType +) + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" +$policiesUri = "config/policies/"; +$contentType = "application/vnd.netbackup+json;version=2.0" +$testPolicyName = "vmware_test_policy" +$testClientName = "MEDIA_SERVER" +$testScheduleName = "vmware_test_schedule" + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +###################################### +# Login to the NetBackup webservices +###################################### + +Function Login() +{ + $uri = $baseUri + "login" + + $body = @{ + userName=$username + password=$password + } + if ($domainName -ne "") { + $body.add("domainName", $domainName) + } + if ($domainType -ne "") { + $body.add("domainType", $domainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $response = (ConvertFrom-Json -InputObject $response) + return $response +} + + +################################################# +# Create a policy with default attribute values, but +# custom schedules, backupselections and clients +################################################# +Function CreatePolicy() +{ + $uri = $baseUri + $policiesUri + + $clients = @{ + hardware="VMware" + hostName="MEDIA_SERVER" + OS="VMware" + } + + $backupSelections = "vmware:/?filter=Displayname Contains 'rsv' OR Displayname Contains 'mtv'" + + $schedules = @{ + scheduleName="sched-9-weeks" + acceleratorForcedRescan=$false + backupCopies=@{ + priority=9999 + copies=@(@{ + mediaOwner="owner1" + storage=$null + retentionPeriod=@{ + value=9 + unit="WEEKS" + } + volumePool="NetBackup" + failStrategy="Continue" + } + ) + } + backupType="Full Backup" + excludeDates=@{ + lastDayOfMonth=$true + recurringDaysOfWeek=@("4:6", "2:5") + recurringDaysOfMonth=@(10) + specificDates=@("2000-1-1", "2016-2-30") + } + frequencySeconds=4800 + includeDates=@{ + lastDayOfMonth=$true + recurringDaysOfWeek=@("2:3", "3:4") + recurringDaysOfMonth=@(10,13) + specificDates=@("2016-12-31") + } + mediaMultiplexing=2 + retriesAllowedAfterRunDay=$true + scheduleType="Calendar" + snapshotOnly=$false + startWindow=@(@{dayOfWeek=1 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=2 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=3 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=4 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=5 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=6 + startSeconds=14600 + durationSeconds=24600}, + @{dayOfWeek=7 + startSeconds=14600 + durationSeconds=24600} + ) + syntheticBackup=$false + storageIsSLP=$false + } + + $policy = @{ + policyName=$testPolicyName + policyType="VMware" + policyAttributes=@{} + clients=@($clients) + schedules=@($schedules) + backupSelections=@{selections=@($backupSelections)} + } + + $data = @{ + type="policy" + id=$testPolicyName + attributes=@{policy=$policy} + } + + $body = @{data=$data} | ConvertTo-Json -Depth 9 + + Write-Host "`nSending a POST request to create $testPolicyName..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to create policy $testPolicyName." + } + + Write-Host "$testPolicyName created successfully.`n" + $response = (ConvertFrom-Json -InputObject $response) +} + +##################### +# List all policies +##################### +Function ListPolicies() +{ + $uri = $baseUri + $policiesUri + + Write-Host "`nSending a GET request to list all policies...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to list policies.`n" + } + + Write-Host $response +} + +################# +# Read a policy +################# +Function ReadPolicy() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + + Write-Host "`nSending a GET request to read policy $testPolicyName...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to read policy $testPolicyName.`n" + } + + Write-Host $response +} + +################### +# Delete a policy +################### +Function DeletePolicy() +{ + $uri = $baseUri + $policiesUri + $testPolicyName + + Write-Host "`nSending a DELETE request to delete policy $testPolicyName..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to delete policy $testPolicyName.`n" + } + + Write-Host "$testPolicyName deleted successfully.`n" +} + +Setup +$loginResponse = Login +$headers = @{"Authorization" = $loginResponse.token} +CreatePolicy +ListPolicies +ReadPolicy +DeletePolicy +ListPolicies diff --git a/recipes/powershell/rbac_filtering_in_policy.ps1 b/recipes/powershell/policies/rbac_filtering_in_policy.ps1 similarity index 94% rename from recipes/powershell/rbac_filtering_in_policy.ps1 rename to recipes/powershell/policies/rbac_filtering_in_policy.ps1 index 7773dae..00d0431 100755 --- a/recipes/powershell/rbac_filtering_in_policy.ps1 +++ b/recipes/powershell/policies/rbac_filtering_in_policy.ps1 @@ -1,456 +1,456 @@ -<# -.SYNOPSIS -This sample script demonstrates the use of NetBackup Policy REST APIs. -.DESCRIPTION -This script can be run using NetBackup 8.1.2 and higher. -.EXAMPLE -./rbac_filtering_in_policy.ps1 -nbmaster -username -password [-domainName -domainType ] -#> - -#Requires -Version 4.0 - -Param ( - [string]$nbmaster = $(Throw "Please specify the name of the NetBackup Master Server using the -nbmaster parameter."), - [string]$username = $(Throw "Please specify the user name using the -username parameter."), - [string]$password = $(Throw "Please specify the password using the -password parameter."), - [string]$domainName, - [string]$domainType -) - -#################### -# Global Variables -#################### - -$port = 1556 -$baseUri = "https://" + $nbmaster + ":" + $port + "/netbackup/" -$policiesUri = "config/policies/"; -$contentType = "application/vnd.netbackup+json;version=2.0" -$testVMwarePolicyName = "vmware_test_policy" -$testOraclePolicyName = "oracle_test_policy" -$testClientName = "MEDIA_SERVER" -$testScheduleName = "vmware_test_schedule" -$global:objectGroupId = "" -$global:accessRuleId = "" - -############################################################### -# Setup to allow self-signed certificates and enable TLS v1.2 -############################################################### -Function Setup() -{ - # Allow self-signed certificates - if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') - { - Add-Type -TypeDefinition @" - using System.Net; - using System.Security.Cryptography.X509Certificates; - public class TrustAllCertsPolicy : ICertificatePolicy { - public bool CheckValidationResult( - ServicePoint srvPoint, X509Certificate certificate, - WebRequest request, int certificateProblem) { - return true; - } - } -"@ - [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy - } - - # Force TLS v1.2 - try { - if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - } - } - catch { - Write-Host "`n"$_.Exception.InnerException.Message - } -} - -###################################### -# Login to the NetBackup webservices -###################################### - -Function Login() -{ - $uri = $baseUri + "login" - - $body = @{ - userName=$username - password=$password - } - if ($domainName -ne "") { - $body.add("domainName", $domainName) - } - if ($domainType -ne "") { - $body.add("domainType", $domainType) - } - Write-Host "`nSending a POST request to login to the NetBackup webservices..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body (ConvertTo-Json -InputObject $body) ` - -ContentType $contentType - - if ($response.StatusCode -ne 201) - { - throw "Unable to connect to the NetBackup Master Server" - } - - Write-Host "Login successful.`n" - $response = (ConvertFrom-Json -InputObject $response) - return $response -} - -################################################# -# Create a vmware policy with default attribute values -################################################# -Function CreateVMwarePolicy() -{ - $uri = $baseUri + $policiesUri - - $policy = @{ - policyName=$testVMwarePolicyName - policyType="VMware" - } - - $data = @{ - type="policy" - id=$testVMwarePolicyName - attributes=@{policy=$policy} - } - - $body = @{data=$data} | ConvertTo-Json -Depth 9 - - Write-Host "`nSending a POST request to create $testVMwarePolicyName..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - Write-Host "Unable to create policy $testVMwarePolicyName." - } else { - Write-Host "$testVMwarePolicyName created successfully.`n" - } - $response = (ConvertFrom-Json -InputObject $response) -} - -################################################# -# Create an oracle policy with default attribute values -################################################# -Function CreateOraclePolicy() -{ - $uri = $baseUri + $policiesUri - - $policy = @{ - policyName=$testOraclePolicyName - policyType="Oracle" - } - - $data = @{ - type="policy" - id=$testOraclePolicyName - attributes=@{policy=$policy} - } - - $body = @{data=$data} | ConvertTo-Json -Depth 9 - - Write-Host "`nSending a POST request to create $testOraclePolicyName..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - Write-Host "Unable to create policy $testOraclePolicyName." - } else { - Write-Host "$testOraclePolicyName created successfully.`n" - } - - $response = (ConvertFrom-Json -InputObject $response) -} - -##################### -# List all policies -##################### -Function ListPolicies() -{ - $uri = $baseUri + $policiesUri - - Write-Host "`nSending a GET request to list all policies...`n" - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method GET ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 200) - { - Write-Host "Unable to list policies.`n" - } else { - Write-Host $response - } - -} - -################# -# Read a policy -################# -Function ReadPolicy() -{ - $uri = $baseUri + $policiesUri + $testVMwarePolicyName - - Write-Host "`nSending a GET request to read policy $testVMwarePolicyName...`n" - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method GET ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 200) - { - throw "Unable to read policy $testVMwarePolicyName.`n" - } - - Write-Host $response -} - -################### -# Delete a vmware policy -################### -Function DeleteVMwarePolicy() -{ - $uri = $baseUri + $policiesUri + $testVMwarePolicyName - - Write-Host "`nSending a DELETE request to delete policy $testVMwarePolicyName..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method DELETE ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to delete policy $testVMwarePolicyName.`n" - } - - Write-Host "$testVMwarePolicyName deleted successfully.`n" -} - -################### -# Delete an oracle policy -################### -Function DeleteOraclePolicy() -{ - $uri = $baseUri + $policiesUri + $testOraclePolicyName - - Write-Host "`nSending a DELETE request to delete policy $testOraclePolicyName..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method DELETE ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to delete policy $testOraclePolicyName.`n" - } - - Write-Host "$testOraclePolicyName deleted successfully.`n" -} - -################################################# -# Create an object group to access VMware policy -################################################# -Function CreateRbacObjectGroupForVMwarePolicy() -{ - $uri = $baseUri + "/rbac/object-groups" - - $criteria = @{ - objectCriterion="policyType eq 40" - objectType="NBPolicy" - } - - $data = @{ - type="object-group" - attributes=@{ - name="VMwarePolicy" - criteria=@($criteria) - } - } - - $body = @{data=$data} | ConvertTo-Json -Depth 9 - - Write-Host "`nMaking POST Request to create object group to access only VMware policies..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 201) - { - throw "Unable to create object group." - } - - Write-Host "VMwarePolicy object group created successfully.`n" - $response = (ConvertFrom-Json -InputObject $response) - $global:objectGroupId = $response.data.id -} - -################################################# -# Create a bpnbat user -################################################# -Function CreateBpnbatUser([string]$username, [string]$domain, [string]$password) -{ - - $paramValue = "$username $password $domain" - $command = 'C:/\"Program Files\"/Veritas/NetBackup/bin/bpnbat.exe' + " -AddUser $paramValue" - Invoke-Expression $command - - Write-Host "Bpnbat user ran successfully.`n" -} - -################################################# -# Create access rule for a user with object group -################################################# -Function CreateRbacAccessRules() -{ - $uri = $baseUri + "/rbac/access-rules" - - $data = @{ - type="access-rule" - attributes=@{ - description="adding VMwarePolicy object group" - } - relationships=@{ - userPrincipal=@{ - data=@{ - type="user-principal" - id="rmnus:testuser:vx:testuser" - } - } - objectGroup=@{ - data=@{ - type="object-group" - id="$global:objectGroupId" - } - } - role=@{ - data=@{ - type="role" - id="3" - } - } - } - } - - $body = @{data=$data} | ConvertTo-Json -Depth 9 - - Write-Host "`nMaking POST Request to create access rule..." - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method POST ` - -Body $body ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 201) - { - throw "Unable to create access rule." - } - - $response = (ConvertFrom-Json -InputObject $response) - $global:accessRuleId = $response.data.id - Write-Host "Access rule is created with id [$global:accessRuleId] to access only VMware policies with status code.`n" -} - -################### -# Delete an object group -################### -Function DeleteRbacObjectGroupForVMwarePolicy() -{ - $uri = $baseUri + "/rbac/object-groups/" + $global:objectGroupId - - Write-Host "`nMaking DELETE Request to remove the object group $global:objectGroupId..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method DELETE ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to delete object group $global:objectGroupId.`n" - } - - Write-Host "$global:objectGroupId deleted successfully.`n" -} - -################### -# Delete the access rule -################### -Function DeleteRbacAccessRule() -{ - $uri = $baseUri + "/rbac/access-rules/" + $global:accessRuleId - - Write-Host "`nMaking DELETE Request to remove the access rule $global:accessRuleId..." - - $response = Invoke-WebRequest ` - -Uri $uri ` - -Method DELETE ` - -ContentType $contentType ` - -Headers $headers - - if ($response.StatusCode -ne 204) - { - throw "Unable to delete access rule $global:accessRuleId.`n" - } - - Write-Host "$global:accessRuleId access rule deleted successfully.`n" -} - -Setup -$loginResponse = Login - -#-------------------------------------------------------------- # -# Create a new rbac user locally using bpnbat to assign object -# level permissions to the newly created user and perform -# subsequent operations. -# -------------------------------------------------------------- # -$username = "testuser" -$password = "testpass" -$domainName = "rmnus" -$domainType = "vx" - -$headers = @{"Authorization" = $loginResponse.token} -CreateRbacObjectGroupForVMwarePolicy -CreateBpnbatUser $username $domainName $password -CreateRbacAccessRules - -CreateVMwarePolicy -CreateOraclePolicy -ListPolicies - -$new_rbac_loginResponse = Login -$headers = @{"Authorization" = $new_rbac_loginResponse.token} -ListPolicies -CreateOraclePolicy -DeleteVMwarePolicy -CreateVMwarePolicy - -$headers = @{"Authorization" = $loginResponse.token} -DeleteVMwarePolicy -DeleteOraclePolicy -DeleteRbacAccessRule -DeleteRbacObjectGroupForVMwarePolicy +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup Policy REST APIs. +.DESCRIPTION +This script can be run using NetBackup 8.1.2 and higher. +.EXAMPLE +./rbac_filtering_in_policy.ps1 -MasterServer -username -password [-domainName -domainType ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$MasterServer = $(Throw "Please specify the name of the NetBackup Master Server using the -MasterServer parameter."), + [string]$username = $(Throw "Please specify the user name using the -username parameter."), + [string]$password = $(Throw "Please specify the password using the -password parameter."), + [string]$domainName, + [string]$domainType +) + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $MasterServer + ":" + $port + "/netbackup/" +$policiesUri = "config/policies/"; +$contentType = "application/vnd.netbackup+json;version=2.0" +$testVMwarePolicyName = "vmware_test_policy" +$testOraclePolicyName = "oracle_test_policy" +$testClientName = "MEDIA_SERVER" +$testScheduleName = "vmware_test_schedule" +$global:objectGroupId = "" +$global:accessRuleId = "" + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +###################################### +# Login to the NetBackup webservices +###################################### + +Function Login() +{ + $uri = $baseUri + "login" + + $body = @{ + userName=$username + password=$password + } + if ($domainName -ne "") { + $body.add("domainName", $domainName) + } + if ($domainType -ne "") { + $body.add("domainType", $domainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $response = (ConvertFrom-Json -InputObject $response) + return $response +} + +################################################# +# Create a vmware policy with default attribute values +################################################# +Function CreateVMwarePolicy() +{ + $uri = $baseUri + $policiesUri + + $policy = @{ + policyName=$testVMwarePolicyName + policyType="VMware" + } + + $data = @{ + type="policy" + id=$testVMwarePolicyName + attributes=@{policy=$policy} + } + + $body = @{data=$data} | ConvertTo-Json -Depth 9 + + Write-Host "`nSending a POST request to create $testVMwarePolicyName..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + Write-Host "Unable to create policy $testVMwarePolicyName." + } else { + Write-Host "$testVMwarePolicyName created successfully.`n" + } + $response = (ConvertFrom-Json -InputObject $response) +} + +################################################# +# Create an oracle policy with default attribute values +################################################# +Function CreateOraclePolicy() +{ + $uri = $baseUri + $policiesUri + + $policy = @{ + policyName=$testOraclePolicyName + policyType="Oracle" + } + + $data = @{ + type="policy" + id=$testOraclePolicyName + attributes=@{policy=$policy} + } + + $body = @{data=$data} | ConvertTo-Json -Depth 9 + + Write-Host "`nSending a POST request to create $testOraclePolicyName..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + Write-Host "Unable to create policy $testOraclePolicyName." + } else { + Write-Host "$testOraclePolicyName created successfully.`n" + } + + $response = (ConvertFrom-Json -InputObject $response) +} + +##################### +# List all policies +##################### +Function ListPolicies() +{ + $uri = $baseUri + $policiesUri + + Write-Host "`nSending a GET request to list all policies...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + Write-Host "Unable to list policies.`n" + } else { + Write-Host $response + } + +} + +################# +# Read a policy +################# +Function ReadPolicy() +{ + $uri = $baseUri + $policiesUri + $testVMwarePolicyName + + Write-Host "`nSending a GET request to read policy $testVMwarePolicyName...`n" + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 200) + { + throw "Unable to read policy $testVMwarePolicyName.`n" + } + + Write-Host $response +} + +################### +# Delete a vmware policy +################### +Function DeleteVMwarePolicy() +{ + $uri = $baseUri + $policiesUri + $testVMwarePolicyName + + Write-Host "`nSending a DELETE request to delete policy $testVMwarePolicyName..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to delete policy $testVMwarePolicyName.`n" + } + + Write-Host "$testVMwarePolicyName deleted successfully.`n" +} + +################### +# Delete an oracle policy +################### +Function DeleteOraclePolicy() +{ + $uri = $baseUri + $policiesUri + $testOraclePolicyName + + Write-Host "`nSending a DELETE request to delete policy $testOraclePolicyName..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to delete policy $testOraclePolicyName.`n" + } + + Write-Host "$testOraclePolicyName deleted successfully.`n" +} + +################################################# +# Create an object group to access VMware policy +################################################# +Function CreateRbacObjectGroupForVMwarePolicy() +{ + $uri = $baseUri + "/rbac/object-groups" + + $criteria = @{ + objectCriterion="policyType eq 40" + objectType="NBPolicy" + } + + $data = @{ + type="object-group" + attributes=@{ + name="VMwarePolicy" + criteria=@($criteria) + } + } + + $body = @{data=$data} | ConvertTo-Json -Depth 9 + + Write-Host "`nMaking POST Request to create object group to access only VMware policies..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 201) + { + throw "Unable to create object group." + } + + Write-Host "VMwarePolicy object group created successfully.`n" + $response = (ConvertFrom-Json -InputObject $response) + $global:objectGroupId = $response.data.id +} + +################################################# +# Create a bpnbat user +################################################# +Function CreateBpnbatUser([string]$username, [string]$domain, [string]$password) +{ + + $paramValue = "$username $password $domain" + $command = 'C:/\"Program Files\"/Veritas/NetBackup/bin/bpnbat.exe' + " -AddUser $paramValue" + Invoke-Expression $command + + Write-Host "Bpnbat user ran successfully.`n" +} + +################################################# +# Create access rule for a user with object group +################################################# +Function CreateRbacAccessRules() +{ + $uri = $baseUri + "/rbac/access-rules" + + $data = @{ + type="access-rule" + attributes=@{ + description="adding VMwarePolicy object group" + } + relationships=@{ + userPrincipal=@{ + data=@{ + type="user-principal" + id="rmnus:testuser:vx:testuser" + } + } + objectGroup=@{ + data=@{ + type="object-group" + id="$global:objectGroupId" + } + } + role=@{ + data=@{ + type="role" + id="3" + } + } + } + } + + $body = @{data=$data} | ConvertTo-Json -Depth 9 + + Write-Host "`nMaking POST Request to create access rule..." + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body $body ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 201) + { + throw "Unable to create access rule." + } + + $response = (ConvertFrom-Json -InputObject $response) + $global:accessRuleId = $response.data.id + Write-Host "Access rule is created with id [$global:accessRuleId] to access only VMware policies with status code.`n" +} + +################### +# Delete an object group +################### +Function DeleteRbacObjectGroupForVMwarePolicy() +{ + $uri = $baseUri + "/rbac/object-groups/" + $global:objectGroupId + + Write-Host "`nMaking DELETE Request to remove the object group $global:objectGroupId..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to delete object group $global:objectGroupId.`n" + } + + Write-Host "$global:objectGroupId deleted successfully.`n" +} + +################### +# Delete the access rule +################### +Function DeleteRbacAccessRule() +{ + $uri = $baseUri + "/rbac/access-rules/" + $global:accessRuleId + + Write-Host "`nMaking DELETE Request to remove the access rule $global:accessRuleId..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + + if ($response.StatusCode -ne 204) + { + throw "Unable to delete access rule $global:accessRuleId.`n" + } + + Write-Host "$global:accessRuleId access rule deleted successfully.`n" +} + +Setup +$loginResponse = Login + +#-------------------------------------------------------------- # +# Create a new rbac user locally using bpnbat to assign object +# level permissions to the newly created user and perform +# subsequent operations. +# -------------------------------------------------------------- # +$username = "testuser" +$password = "testpass" +$domainName = "rmnus" +$domainType = "vx" + +$headers = @{"Authorization" = $loginResponse.token} +CreateRbacObjectGroupForVMwarePolicy +CreateBpnbatUser $username $domainName $password +CreateRbacAccessRules + +CreateVMwarePolicy +CreateOraclePolicy +ListPolicies + +$new_rbac_loginResponse = Login +$headers = @{"Authorization" = $new_rbac_loginResponse.token} +ListPolicies +CreateOraclePolicy +DeleteVMwarePolicy +CreateVMwarePolicy + +$headers = @{"Authorization" = $loginResponse.token} +DeleteVMwarePolicy +DeleteOraclePolicy +DeleteRbacAccessRule +DeleteRbacObjectGroupForVMwarePolicy diff --git a/recipes/powershell/storage/README.md b/recipes/powershell/storage/README.md new file mode 100644 index 0000000..99015e9 --- /dev/null +++ b/recipes/powershell/storage/README.md @@ -0,0 +1,17 @@ +### NetBackup API Code Samples for PowerShell + +This directory contains code samples to invoke NetBackup REST APIs using PowerShell. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Executing the recipes in PowerShell + +Pre-requisites: +- NetBackup 8.1.2 or higher +- PowerShell 4.0 or higher +- NetBackup 8.2 or higher is required for configuring storage API + +Use the following commands to run the PowerShell samples. +- `.\configure_storage_unit_end_to_end.ps1 -nbmaster -username -password [-domainName -domainType ]` diff --git a/recipes/powershell/storage/configure_storage_unit_end_to_end.ps1 b/recipes/powershell/storage/configure_storage_unit_end_to_end.ps1 new file mode 100644 index 0000000..d38b2f5 --- /dev/null +++ b/recipes/powershell/storage/configure_storage_unit_end_to_end.ps1 @@ -0,0 +1,347 @@ +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup Storage management REST APIs. +.DESCRIPTION +This script can be run using NetBackup 8.2 and higher. +It demonstrate how to create a storage server, disk pool and storage unit by specifying json payload string in each specified function. +.EXAMPLE +./configure_storage_unit_end_to_end.ps1 -nbmaster -username -password [-domainName -domainType ] +#> + +#Requires -Version 4.0 + +Param ( + [string]$nbmaster = $(Throw "Please specify the name of the NetBackup Master Server using the -nbmaster parameter."), + [string]$username = $(Throw "Please specify the user name using the -username parameter."), + [string]$password = $(Throw "Please specify the password using the -password parameter."), + [string]$domainName, + [string]$domainType +) + +#################### +# Global Variables +#################### + +$port = 1556 +$baseUri = "https://" + $nbmaster + ":" + $port + "/netbackup/" +$contentType = "application/vnd.netbackup+json;version=3.0" + +############################################################### +# Setup to allow self-signed certificates and enable TLS v1.2 +############################################################### +Function Setup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + } + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host "`n"$_.Exception.InnerException.Message + } +} + +###################################### +# Login to the NetBackup webservices +###################################### + +Function Login() +{ + $uri = $baseUri + "login" + + $body = @{ + userName=$username + password=$password + } + if ($domainName -ne "") { + $body.add("domainName", $domainName) + } + if ($domainType -ne "") { + $body.add("domainType", $domainType) + } + Write-Host "`nSending a POST request to login to the NetBackup webservices..." + + $response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $contentType + + if ($response.StatusCode -ne 201) + { + throw "Unable to connect to the NetBackup Master Server" + } + + Write-Host "Login successful.`n" + $response = (ConvertFrom-Json -InputObject $response) + return $response +} + + +################################################# +# Create a cloud storage server +################################################# +Function CreateStorageServer() +{ + $sts_uri = $baseUri + "/storage/storage-servers" + + $sts_cloud_json = '{ + "data": { + "type": "storageServer", + "attributes": { + "name": "amazonstss.com", + "storageCategory": "CLOUD", + "mediaServerDetails": { + "name": "MEDIA_SERVER" + }, + "cloudAttributes": { + "providerId": "amazon", + "compressionEnabled": true, + "s3RegionDetails": [ + { + "serviceHost": "SERVICE-HOST", + "regionName": "REGION_NAME", + "regionId": "REGION_ID" + } + ], + "cloudCredentials": { + "authType": "ACCESS_KEY", + "accessKeyDetails": { + "userName": "USER_ID", + "password": "PASSWORD" + } + } + } + } + } + } + + + ' + + $response_create_sts = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($sts_cloud_json) ` + -ContentType $contentType ` + -Headers $headers + + if ($response_create_sts.StatusCode -ne 201) + { + throw "Unable to create storage server." + } + + Write-Host "storage server created successfully.`n" + echo $response_create_sts + Write-Host $response_create_sts + + $response_create_sts = (ConvertFrom-Json -InputObject $response_create_sts) +} + +################################################# +# Create a disk pool for cloud storage server +################################################# +Function CreateDiskPool() +{ + + $dp_uri = $baseUri + "/storage/disk-pools" + + $dp_cloud_json = '{ + "data": { + "type": "diskPool", + "attributes": { + "name": "disk-pool1", + "diskVolumes": [ + { + "name": "VOLUME_NAME" + } + ], + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 4 + } + }, + "relationships": { + "storageServers": { + "data": [ + { + "type": "storageServer", + "id": "STORAGE_SERVER_ID" + } + ] + } + } + } + } + + + ' + + $response_create_dp = Invoke-WebRequest ` + -Uri $dp_uri ` + -Method POST ` + -Body ($dp_cloud_json) ` + -ContentType $contentType ` + -Headers $headers + + if ($response_create_dp.StatusCode -ne 201) + { + throw "Unable to create Disk Pool." + } + + Write-Host "Disk Pool created successfully.`n" + echo $response_create_dp + Write-Host $response_create_dp + + $response_create_dp = (ConvertFrom-Json -InputObject $response_create_dp) +} + +#################################################################################### +# Create a storage unit for cloud torage server +#################################################################################### +Function CreateStorageUnit() +{ + $stu_uri = $baseUri + "/storage/storage-units" + + $stu_cloud_json = '{ + "data": { + "type": "storageUnit", + "attributes": { + "name": "cloud-stu", + "useAnyAvailableMediaServer": true, + "maxFragmentSizeMegabytes": 50000, + "maxConcurrentJobs": 10, + "onDemandOnly": true + }, + "relationships": { + "diskPool": { + "data" : { + "type": "diskPool", + "id": "STORAGE_SERVER_ID" + } + } + } + } + } + ' + + $response_create_stu = Invoke-WebRequest ` + -Uri $stu_uri ` + -Method POST ` + -Body ($stu_cloud_json) ` + -ContentType $contentType ` + -Headers $headers + + if ($response_create_stu.StatusCode -ne 201) + { + throw "Unable to create storage unit." + } + + Write-Host "storage unit created successfully.`n" + echo $response_create_stu + Write-Host $response_create_stu + + $response_create_stu = (ConvertFrom-Json -InputObject $response_create_stu) +} + +######################################################################## +# List all Storage Servers +######################################################################## +Function ListAllStorageServer() +{ + $sts_uri = $baseUri + "/storage/storage-servers" + + + $response_getAll_sts = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response_getAll_sts.StatusCode -ne 200) + { + throw "Unable to fetch storage servers." + } + + Write-Host "storage servers fetched successfully.`n" + Write-Host $response_getAll_sts + + $response_getAll_sts = (ConvertFrom-Json -InputObject $response_getAll_sts) +} + +########################################################################### +# List all Disk Pools +########################################################################### +Function ListAllDiskPools() +{ + $dp_uri = $baseUri + "/storage/disk-pools" + + + $response_getAll_dp = Invoke-WebRequest ` + -Uri $dp_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response_getAll_dp.StatusCode -ne 200) + { + throw "Unable to fetch disk pools." + } + + Write-Host "disk pools fetched successfully.`n" + Write-Host $response_getAll_dp + + $response_getAll_dp = (ConvertFrom-Json -InputObject $response_getAll_dp) +} + +############################################################################## +# List all Storage Units +############################################################################## +Function ListAllStorageUnits() +{ + $stu_uri = $baseUri + "/storage/storage-units" + + $response_getAll_stu = Invoke-WebRequest ` + -Uri $stu_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + + if ($response_getAll_stu.StatusCode -ne 200) + { + throw "Unable to fetch storage units." + } + + Write-Host "storage units fetched successfully.`n" + Write-Host $response_getAll_stu + + $response_getAll_stu = (ConvertFrom-Json -InputObject $response_getAll_stu) +} + +Setup +$loginResponse = Login +$headers = @{"Authorization" = $loginResponse.token} +CreateStorageServer +ListAllStorageServer +CreateDiskPool +ListAllDiskPools +CreateStorageUnit +ListAllStorageUnits \ No newline at end of file diff --git a/recipes/python/ClientBackup.py3 b/recipes/python/ClientBackup.py3 new file mode 100644 index 0000000..f839f5f --- /dev/null +++ b/recipes/python/ClientBackup.py3 @@ -0,0 +1,246 @@ +#!/usr/bin/python3 +# +# SYNOPSIS +# This sample script demonstrates the use of NetBackup REST API for launching +# a manual backup from a Windows client system + +# DESCRIPTION +# This script will query the master server for policy information and existing +# client backup images. If the latest full backup is older than the +# frequency defined within the policy schedule a full backup will be + +# launched; otherwise, an incremental backup will be performed. +# EXAMPLE +# ./ClientBackup.py3 -p "ExampleClientBackup-Std" -k "AybRCz3UE_YOpCFD7_5mzQQfJsRXj_pN6WXLA7boX4EAuKD_kwBfXWQ5bFNWDiuJ" +# +# Requirements and comments for running this script +# Tested with Python 3.8 +# Tested with NetBackup 8.3.0.1 +# NetBackup client software already installed, configured and tested +# A policy must be defined on the master server with the following details +# Policy type must be Standard +# 2 schedules define with no backup windows +# one full named FULL +# one incremental named INCR +# Client name added to Clients tab +# Use command line parameters to specify the following parameters +# -p (to reference above policy) +# -k (API key generated through NetBackup web UI) +# API key uesr must have following minimum privileges assigned to it's role: +# Global -> NetBackup management -> NetBackup images -> View +# Global -> Protection -> Policies -> View +# Global -> Protection -> Policies -> Manual Backup + +import sys +import argparse +from datetime import datetime, timedelta +import json +import requests +requests.packages.urllib3.disable_warnings() +from urllib.parse import quote + +################################################################ +# Parsing the command line to get the policy and API key +################################################################ +parser = argparse.ArgumentParser() +parser.add_argument("-p", dest='policy', metavar='POLICY', required=True, help="backup policy to run manual backup with") +parser.add_argument("-k", dest='apikey', metavar='APIKEY', required=True, help="specify API key") +parser.add_argument("-t", dest='test', action="store_true", help="test mode, don't run backup") +parser.add_argument("-v", dest='verbose', action="store_true", help="verbose output") +cli_args=parser.parse_args() + +if cli_args.verbose : + print("Policy specified: {}.".format(cli_args.policy)) + print("API key specified: {}.".format(cli_args.apikey)) + print("Test mode?: {}.".format(cli_args.test)) + print("Verbose?: {}.".format(cli_args.verbose)) + +################################################################ +# Looking for the /usr/openv/netbackup/bp.conf file for SERVER and CLIENT +# entries. Only want to get the first entry for either one +################################################################ +nbmaster=False +clientname=False +with open('/usr/openv/netbackup/bp.conf','r') as fh: + for cnt, line in enumerate(fh): + data = line.split('=') + if not nbmaster and data[0].strip() == 'SERVER' : + nbmaster=data[1].strip() + if not clientname and data[0].strip() == 'CLIENT_NAME' : + clientname = data[1].strip() + +if cli_args.verbose : + print("nbmaster={}.".format(nbmaster)) + print("clientname={}.".format(clientname)) + print("") + +################################################################ +# Setting some variables to be used through the rest of the processing +################################################################ +port="1556" +basepath = "https://" + nbmaster + ":" + port + "/netbackup" +content_type = "application/vnd.netbackup+json;version=4.0" +days2lookback = 30 +fullname = "FULL" +incrname = "INCR" +if cli_args.verbose : + print("Base URI = {}".format(basepath)) + print("Looking back {} days for previous backups".format(str(days2lookback))) + print("") + +################################################################ +# Getting the policy details for this policy +################################################################ +uri = basepath + "/config/policies/" + cli_args.policy +if cli_args.verbose : + print("Getting {} policy details".format(cli_args.policy)) + print("User URI {}".format(uri)) +header = { + "Authorization": cli_args.apikey , + "Accept": content_type +} +response = requests.get(uri, headers=header, verify=False) +if response.status_code != 200 : + print("Unable to get the list of NetBackup images!") + sys.exit() + +content = response.json() +for schedule in content['data']['attributes']['policy']['schedules'] : + if schedule['scheduleName'] == fullname : + fullfrequency = schedule['frequencySeconds'] + fullschedule = schedule['scheduleName'] + if schedule['scheduleName'] == incrname : + incrfrequency = schedule['frequencySeconds'] + incrschedule = schedule['scheduleName'] + +if cli_args.verbose : + print("Incremental schedule {} frequency is {} seconds".format(incrschedule,incrfrequency)) + print("Full schedule {} frequency is {} seconds".format(fullschedule,fullfrequency)) + +################################################################ +# Getting backup images for this client +################################################################ +uri = basepath + "/catalog/images" +if cli_args.verbose : + print("Looking for most recent backup images to see what kind of backup to run") + print("using URI {}".format(uri)) + +# Note that currentDate and lookbackDate are DateTime objects while +# backupTimeStart and backupTimeEnd are string date in ISO 8601 format +# using Zulu (Greenwich Mean Time) time: YYYY-MM-DDThh:mm:ssZ +# Date/Time format example: +# November 19, 1969 at 3:22:00 PM = 1969-11-19T15:22:00Z +# currentDate and backupTimeStart are both datetime objects +# Getting current date +currentDate = datetime.utcnow() +# Set starting date to 30 days from current date +backupTimeStart = currentDate - timedelta(days=days2lookback) + +if cli_args.verbose : + print("currentDate = {}Z".format(currentDate.isoformat())) + print("backupTimeStart = {}Z.".format(backupTimeStart.isoformat())) + +# Because the filter query requires use of %20 for space instead of + +# have to use the quote method to properly substitute this instead of native +# library from requests. +page_limit=quote("page[limit]")+"=50"; +filter="filter="+quote("clientName eq '{}' and backupTime ge {}Z".format(clientname,backupTimeStart.isoformat())) +header = { + "Authorization": cli_args.apikey +} + +# Build out the actual URL with filter and page_limit +url=uri+"?"+page_limit+"&"+filter +response=requests.get(url, headers=header, verify=False) +if response.status_code != 200 : + print("Unable to get list of NetBackup images!") + sys.exit() + +content=response.json() +#print(content) +#print(content['data']) + +schedulerun="none" +fulltime=datetime.strptime("2000-01-01", "%Y-%m-%d") +incrtime=datetime.strptime("2000-01-01", "%Y-%m-%d") +for image in content['data'] : + # Converting image timestamp to datetime object + a=datetime.strptime(image['attributes']['backupTime'], "%Y-%m-%dT%H:%M:%S.000Z") + if image['attributes']['scheduleName'] == fullname : + if a > fulltime : + fulltime=a + if image['attributes']['scheduleName'] == incrname : + if a > incrtime : + incrtime=a + +# Define the full and incr window by subtracting the schedule frequency from +# the current time. +fullwindow = currentDate - timedelta(seconds=fullfrequency) +incrwindow = currentDate - timedelta(seconds=incrfrequency) + +# Now, run through the logic to determine what kind of backup to run +if fulltime.strftime("%Y-%m-%d") == "2000-01-01" : + # No recent backup images found for this client, run full backup + schedulerun = fullname +elif fullwindow >= fulltime : + # Found a FULL backup older than the current full window + schedulerun = fullname +elif fulltime.strftime("%Y-%m-%d") != "2000-01-01" and incrtime.strftime("%Y-%m-%d") == "2000-01-01" : + # Full backup found but less than window and no incremental + schedulerun = incrname +elif incrwindow >= incrtime : + # Full backup less than window and incremental older than window + schedulerun = incrname +else : + schedulerun = "none" + +if cli_args.verbose : + print("schedulerun={}.".format(schedulerun)) + print("fulltime={}.".format(fulltime)) + print("incrtime={}.".format(incrtime)) + print("") + +# If schedulerun is equal to none, then skip running anything +if schedulerun == "none" : + print("Too soon to take a backup") + sys.exit() + +################################################################ +# Running this in testing mode which means we don't want to run a backup, +# just see what would be run +################################################################ +if cli_args.test : + sys.exit() + +################################################################ +# Launch the backup now +################################################################ +uri = basepath+"/admin/manual-backup" +if cli_args.verbose : + print("Lauching the backup now") + print("Using URI {}".format(uri)) + +header = { + "Authorization": cli_args.apikey, + "Content-Type": "application/vnd.netbackup+json;version=4.0" +} +backup_dict = { + "data": { + "type": "backupRequest", + "attributes": { + "policyName": cli_args.policy, + "scheduleName": schedulerun, + "clientName": clientname + } + } +} +response=requests.post(uri, data=json.dumps(backup_dict), headers=header, verify=False) + +if response.status_code != 202 : + print("API status code={}".format(response.status_code)) + print("response text={}".format(response.text)) + print("Unable to start the backup for {} with schedule {} for policy {}.".format(clientname,schedulerun,cli_args.policy)) + sys.exit() + +if cli_args.verbose : + print("Backup {} successfully started".format(schedulerun)) diff --git a/recipes/python/README.md b/recipes/python/README.md deleted file mode 100644 index 95b7039..0000000 --- a/recipes/python/README.md +++ /dev/null @@ -1,20 +0,0 @@ -### NetBackup API Code Samples for Python - -This directory contains code samples to invoke NetBackup REST APIs using Python. - -#### Disclaimer - -These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. - -#### Executing the recipes in Python - -Pre-requisites: -- NetBackup 8.1.2 or higher -- python 3.5 or higher -- python modules: `requests` - - -Use the following commands to run the python samples. -- `python -W ignore create_policy_step_by_step.py -nbmaster -username -password [-domainName ] [-domainType ]` -- `python -W ignore create_policy_in_one_step.py -nbmaster -username -password [-domainName ] [-domainType ]` -- `python -W ignore rbac_filtering_in_policy.py -nbmaster -username -password [-domainName ] [-domainType ]` diff --git a/recipes/python/admin/README.md b/recipes/python/admin/README.md new file mode 100644 index 0000000..e2bc47d --- /dev/null +++ b/recipes/python/admin/README.md @@ -0,0 +1,19 @@ +### NetBackup Hosts Administration APIs Code Samples + +This directory contains sample Python scripts that list the details of NetBackup processes and services running on a host using the NetBackup Hosts Administration APIs. + +#### Disclaimer + +These samples are provided only for reference and not meant for production use. + +#### Executing the script + +Pre-requisites: +- NetBackup 8.2 or higher +- Python 3.5 or higher +- Python modules: `requests`. + + +Use the following commands to run the scripts. The commands should be run from the parent directory of this 'admin' directory. +- Get the details of NetBackup processes running on a host (specified by hostName): `python -W ignore -m admin.list_nb_processes -hostName -nbmaster -username -password [-domainName ] [-domainType ]` +- Get the details/status of NetBackup services on a host (specified by hostName): `python -W ignore -m admin.list_nb_services -hostName -nbmaster -username -password [-domainName ] [-domainType ]` diff --git a/recipes/python/admin/list_nb_processes.py b/recipes/python/admin/list_nb_processes.py new file mode 100644 index 0000000..b04f17a --- /dev/null +++ b/recipes/python/admin/list_nb_processes.py @@ -0,0 +1,116 @@ +import sys +import login.login_api as login_api +import config.hosts_api as hosts_api +import admin.processes_api as processes_api + +nbmaster = "" +username = "" +password = "" +domainName = "" +domainType = "" +hostName = "" + +def print_disclaimer(): + print("\n-------------------------------------------------------------------------------------------------") + print("-- This script requires Python3.5 or higher. --") + print("-- The system where this script is run should have Python 3.5 or higher version installed. --") + print("-------------------------------------------------------------------------------------------------") + print("The script requires 'requests' library to make the API calls.") + print("You can install the library using the command: pip install requests") + print("-------------------------------------------------------------------------------------------------") + +def print_usage(): + print("\nCommand-line usage (should be run from the parent directory of the 'admin' directory):") + print("\tpython -Wignore -m admin.list_nb_processes -hostName -nbmaster -username -password [-domainName ] [-domainType ]") + print("Note: hostName is the name of the NetBackup host to get the list of processes.\n") + print("-------------------------------------------------------------------------------------------------") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print("\nInvalid command!") + print_usage() + exit() + + global nbmaster + global username + global password + global domainName + global domainType + global hostName + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-domainName": + domainName = sys.argv[i + 1] + elif sys.argv[i] == "-domainType": + domainType = sys.argv[i + 1] + elif sys.argv[i] == "-hostName": + hostName = sys.argv[i + 1] + else: + print("\nInvalid command!") + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'\n") + exit() + elif username == "": + print("Please provide the value for 'username'\n") + exit() + elif password == "": + print("Please provide the value for 'password'\n") + exit() + elif domainName == "": + print("Please provide the value for 'domainName'\n") + exit() + elif domainType == "": + print("Please provide the value for 'domainType'\n") + exit() + elif hostName == "": + print("Please provide the value for 'hostName'\n") + exit() + +def print_nbprocesses_details(processes): + print("NB PROCESS NAME".rjust(20), end = "\t") + print("PID".rjust(10), end = "\t") + print("MEMORY USAGE (MB)".rjust(10), end = "\t\t") + print("START TIME".rjust(10), end = "\t\t") + print("ELAPSED TIME".rjust(10), end = "\t") + print("PRIORITY".rjust(10)) + print("-----------------------------------------"*3) + for process in processes: + process_attributes = process['attributes'] + print(process_attributes['processName'].rjust(20), end = "\t") + print(str(process_attributes['pid']).rjust(10), end = "\t") + print(str(process_attributes['memoryUsageMB']).rjust(10), end = "\t\t") + print(process_attributes['startTime'].rjust(10), end = "\t\t") + print(process_attributes['elapsedTime'].rjust(10), end = "\t") + print(str(process_attributes['priority']).rjust(10)) + print() + +print_disclaimer() + +print_usage() + +read_command_line_arguments() + +base_url = "https://" + nbmaster + "/netbackup" + +jwt = login_api.perform_login(base_url, username, password, domainName, domainType) + +host_uuid = hosts_api.get_host_uuid(base_url, jwt, nbmaster) + +processes = processes_api.get_all_nb_processes(base_url, jwt, host_uuid) + +processes_data = processes['data'] + +if len(processes_data) > 0: + print_nbprocesses_details(processes_data) +else: + print("\nNo NB processes exist on the specified host!") + diff --git a/recipes/python/admin/list_nb_services.py b/recipes/python/admin/list_nb_services.py new file mode 100644 index 0000000..31d9fee --- /dev/null +++ b/recipes/python/admin/list_nb_services.py @@ -0,0 +1,113 @@ +import sys +import login.login_api as login_api +import config.hosts_api as hosts_api +import admin.services_api as services_api + +nbmaster = "" +username = "" +password = "" +domainName = "" +domainType = "" +hostName = "" + +def print_disclaimer(): + print("\n-------------------------------------------------------------------------------------------------") + print("-- This script requires Python3.5 or higher. --") + print("-- The system where this script is run should have Python 3.5 or higher version installed. --") + print("-------------------------------------------------------------------------------------------------") + print("The script requires 'requests' library to make the API calls.") + print("You can install the library using the command: pip install requests") + print("-------------------------------------------------------------------------------------------------") + +def print_usage(): + print("\nCommand-line usage (should be run from the parent directory of the 'admin' directory):") + print("\tpython -Wignore -m admin.list_nb_services -hostName -nbmaster -username -password [-domainName ] [-domainType ]") + print("Note: hostName is the name of the NetBackup host to get the list of services.\n") + print("-------------------------------------------------------------------------------------------------") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print("\nInvalid command!") + print_usage() + exit() + + global nbmaster + global username + global password + global domainName + global domainType + global hostName + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-domainName": + domainName = sys.argv[i + 1] + elif sys.argv[i] == "-domainType": + domainType = sys.argv[i + 1] + elif sys.argv[i] == "-hostName": + hostName = sys.argv[i + 1] + else: + print("\nInvalid command!") + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'\n") + exit() + elif username == "": + print("Please provide the value for 'username'\n") + exit() + elif password == "": + print("Please provide the value for 'password'\n") + exit() + elif domainName == "": + print("Please provide the value for 'domainName'\n") + exit() + elif domainType == "": + print("Please provide the value for 'domainType'\n") + exit() + elif hostName == "": + print("Please provide the value for 'hostName'\n") + exit() + +def print_nbservices_details(services_data): + print("NB SERVICE NAME".rjust(20), end = "\t") + print("STATUS".rjust(10)) + print("----------------------------------------") + for service in services_data: + print(service['id'].rjust(20), end = "\t") + print(service['attributes']['status'].rjust(10)) + print() + +print_disclaimer() + +print_usage() + +read_command_line_arguments() + +base_url = "https://" + nbmaster + "/netbackup" + +jwt = login_api.perform_login(base_url, username, password, domainName, domainType) + +host_uuid = hosts_api.get_host_uuid(base_url, jwt, nbmaster) + +services = services_api.get_all_nb_services(base_url, jwt, host_uuid) + +data = services['data'] + +if len(data) > 0: + print_nbservices_details(data) +else: + print("\nNo NB services exist on the specified host!") + +##service = admin.services_api_requests.get_specific_nb_service(jwt, uuid, base_url) +## +##data = service['data'] +## +##if len(data) > 0: +## print_nbservice_details(data) diff --git a/recipes/python/admin/processes_api.py b/recipes/python/admin/processes_api.py new file mode 100644 index 0000000..928f226 --- /dev/null +++ b/recipes/python/admin/processes_api.py @@ -0,0 +1,32 @@ +import requests + +content_type = "application/vnd.netbackup+json; version=3.0" + +def get_all_nb_processes(base_url, jwt, host_uuid): + url = base_url + "/admin/hosts/" + host_uuid + "/processes" + headers = {'Content-Type': content_type, 'Authorization': jwt} + print("\nCalling NB Processes API to list the details of all NB processes on the host: {}\n".format(host_uuid)) + + resp = requests.get(url, headers=headers, verify=False) + + if resp.status_code != 200: + print("GET NB Processes API failed with status code {} and {}\n".format(resp.status_code, resp.json())) + raise SystemExit("\n\n") + + return resp.json() + + +def get_specific_nb_service(base_url, jwt, host_uuid, processName): + url = base_url + "/admin/hosts" + host_uuid + "/processes" + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = {'filter': "processName eq '{}'".format(processName)} + + print("\nCalling NB Processes API to get the details of the NB process {} on the host {}".format(processName, host_uuid)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + print('\nGET NB Process API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + raise SystemExit("\n\n") + + return resp.json() diff --git a/recipes/python/admin/services_api.py b/recipes/python/admin/services_api.py new file mode 100644 index 0000000..cd3e96a --- /dev/null +++ b/recipes/python/admin/services_api.py @@ -0,0 +1,31 @@ +import requests + +content_type = "application/vnd.netbackup+json; version=3.0" + +def get_all_nb_services(base_url, jwt, host_uuid): + url = base_url + "/admin/hosts/" + host_uuid + "/services" + headers = {'Content-Type': content_type, 'Authorization': jwt} + print("\nCalling NB Services API to get the details/status of all NB services on the host: {}\n".format(host_uuid)) + + resp = requests.get(url, headers=headers, verify=False) + + if resp.status_code != 200: + print("GET NB Services API failed with status code {} and {}\n".format(resp.status_code, resp.json())) + raise SystemExit("\n\n") + + return resp.json() + + +def get_specific_nb_service(base_url, jwt, host_uuid, serviceName): + url = base_url + "/admin/hosts" + host_uuid + "/services/" + serviceName + headers = {'Content-Type': content_type, 'Authorization': jwt} + + print("\nCalling NB Services API to get the details/status of the NB service {} on the host {}".format(serviceName, host_uuid)) + + resp = requests.get(url, headers=headers, verify=False) + + if resp.status_code != 200: + print("GET NB Service API failed with status code {} and {}\n".format(resp.status_code, resp.json())) + raise SystemExit("\n\n") + + return resp.json() diff --git a/recipes/python/assets/README.md b/recipes/python/assets/README.md new file mode 100644 index 0000000..8180c5f --- /dev/null +++ b/recipes/python/assets/README.md @@ -0,0 +1,59 @@ +### NetBackup Asset Service API Code Samples + +This directory contains Python scripts demonstrating the use of NetBackup Asset Service APIs. + +#### Disclaimer + +The samples are provided only for reference and not meant for production use. + +#### Executing the script + +Prerequisites: +- NetBackup 8.3 or higher +- Python 3.5 or higher +- Python modules: `requests` + +The following are the commands to run the scripts (should be run from the parent directory of this 'assets' directory). + +- get_vmware_assets (Get VMs or VM Groups): + + `python -Wignore -m assets.get_vmware_assets -nbserver -username -password -domainName -domainType [-assetType ] [-assetsFilter ]` + + The script uses the NetBackup Asset Service API to get the VMware workload assets - VMs or VM groups (filtered by the given filter if specified). It prints the following details (delimited by tab): For assetType 'vm' - VM display name, Instance Id, vCenter and the protection plan names that the VM is protected by. For assetType 'vmGroup' - VM group name, VM server, group filter criteria and the protection plan names. + + The assetType option can be either vm or vmGroup. Default is 'vm' if not specified. + The assetsFilter option can be used to filter the assets returned. The filter criteria should be in OData format (refer to the NetBackup API documentation for more details). If not specified, the script will get all the assets. Redirect the script output to a file to avoid printing the details on the terminal. + + Examples: + - Gets all VMs: `python -Wignore -m assets.get_vmware_assets -nbserver localhost -username user -password password -domainName domain -domainType NT > vm_assets.txt` + + - Get the VMs that match the given filter: `python -Wignore -m assets.get_vmware_assets -nbserver localhost -username user -password password -domainName domain -domainType NT -assetsFilter "contains(commonAssetAttributes/displayName, 'backup')" > vm_assets.txt` + + - Get all VM Groups: `python -Wignore -m assets.get_vmware_assets -nbserver localhost -username user -password password -domainName domain -domainType NT -assetType vmGroup > vm_groups.txt` + + - Get the VM Groups that match the given filter: `python -Wignore -m assets.get_vmware_assets -nbserver localhost -username user -password password -domainName domain -domainType NT -assetType vmGroup -assetsFilter "contains(commonAssetAttributes/displayName, 'backup')"` + + +- create_vmware_asset_group (Create VM group and get the VM group by Id): + + `python -Wignore -m assets.create_vmware_asset_group -nbserver -username -password -domainName -domainType -vmGroupName -vmServer [-vmGroupFilter ]` + + The script uses the NetBackup Asset Service API to create VM group and get the VM group details using its asset id. The vmGroupFilter option specifies the filter criteria (in OData format) for the VMs to be included in the group. If it is empty or not specified, all the VMs in the given VM server are included in the group. + If the VM group is created, the script gets the VM group by its asset id and prints the details. + + Examples: + - Create VM group with no filter: `python -Wignore -m assets.create_vmware_asset_group -nbserver localhost -username user -password password -domainName domain -domainType NT -vmGroupName vmGroup1 -vmServer vcenter1` + + - Create VM group with filter: `python -Wignore -m assets.create_vmware_asset_group -nbserver localhost -username user -password password -domainName domain -domainType NT -vmGroupName vmGroup2 -vmServer vcenter2 -vmGroupFilter "contains(commonAssetAttributes/displayName, 'backup')"` + + +- create_oracle_asset (Create Oracle Asset): + + `python -Wignore create_oracle_asset.py -nbserver -username -password [-dbName ] [-addRMANCatalog] [-rmanCatalogName ] [-tnsName ] [-addCredentials ] [-credentialName ]` + + The script uses the NetBackup Asset Service API to add an Oracle database with the given name. Add an RMAN catalog to the database if specified. Also adding credentials to the created assets if specified. It ends with running a database discovery on the primary server. + + Examples: + - Add an Oracle database with existing credentials: `python -Wignore create_oracle_asset.py -nbserver localhost -username username -password password -dbName SampleDB -credentialName ExistingCreds` + + - Add an Oracle database with a new RMAN catalog and new credentials: `python -Wignore create_oracle_asset.py -nbserver localhost -username username -password password -dbName SampleDB -addRMANCatalog -rmanCatalogName catalog -tnsName rmancat -addCredentials os -credentialName OracleCreds` diff --git a/recipes/python/assets/create_oracle_asset.py b/recipes/python/assets/create_oracle_asset.py new file mode 100755 index 0000000..19c2644 --- /dev/null +++ b/recipes/python/assets/create_oracle_asset.py @@ -0,0 +1,244 @@ +# Cred? if doesn't already exist= +# register creds + +## The script can be run with Python 3.11 or higher version. +## The script requires 'requests' library to make the API calls. The library can be installed using the command: pip install requests. + +import argparse +import requests +import time +import os +import json + +content_type = "application/vnd.netbackup+json;version=3.0" + +parser = argparse.ArgumentParser(description="MSSQL Instance backup and Database restore scenario") +parser.add_argument('-nbserver', required=True, help="NetBackup primary server name") +parser.add_argument('-username', required=True, help="NetBackup primary server username") +parser.add_argument('-password', required=True, help="NetBackup primary server password") +parser.add_argument('-domainName', required=False, help="NetBackup primary server login domain name") +parser.add_argument('-domainType', required=False, help="NetBackup primary server login domain type") +parser.add_argument('-dbName', required=False, default="SampleDatabaseName", help="Oracle Database name to create an asset for") +parser.add_argument('-addRMANCatalog', required=False, action='store_true', help="If an RMAN catalog asset should be created") +parser.add_argument('-rmanCatalogName', required=False, default="RMANCatalog", help="RMAN catalog name") +parser.add_argument('-tnsName', required=False, default="rmancat", help="TNS name for RMAN catalog") +parser.add_argument('-addCredentials', required=False, choices=['wallet', 'oracle', 'os', 'osAndOracle'], help="Type of credential to be created for the generated oracle assets") +parser.add_argument('-credentialName', required=False, help="Name of Oracle credentials to be assoiciated with the assets") + +args = parser.parse_args() + +nbserver = args.nbserver +username = args.username +password = args.password +domainName = args.domainName +domainType = args.domainType +dbName = args.dbName +addRMANCatalog = args.addRMANCatalog +tnsName = args.tnsName +rmanCatalogName = args.rmanCatalogName +addCredentials = args.addCredentials +credentialName = args.credentialName + + +base_url = "https://" + nbserver + "/netbackup" +asset_service_url = base_url + "/asset-service/queries/" +credentials_url = base_url + "/config/credentials/" +content_type = content_type = "application/vnd.netbackup+json;version=4.0" + + +def create_oracle_db(databaseName, rmanCatalogId, credentialName): + manual_db_create_request = open_sample_payload("post_oracle_create_db.json") + if rmanCatalogId is not '': + manual_db_create_request['data']['attributes']['parameters']['objectList'][0]['relationship'] = {"rmanCatalog":{"data": [rmanCatalogId]}} + + if credentialName is not '': + manual_db_create_request['data']['attributes']['parameters']['objectList'][0]['asset']['commonAssetAttributes']['credentials']= [{"credentialName": credentialName}] + + manual_db_create_request['data']['attributes']['parameters']['objectList'][0]['asset']['databaseName'] + + oracle_create_db_response = requests.post(asset_service_url, headers=headers, json=manual_db_create_request, verify=False) + + if oracle_create_db_response.status_code is not 201: + print("\nAPI returned status code {}. Response: {}".format(oracle_create_db_response.status_code, + oracle_create_db_response.json())) + raise SystemExit("\nScript ended.\n") + + print ("\nRequest to create Oracle DB has been posted.") + + oracle_db_id_uri = verify_asset_creation(oracle_create_db_response.json()['data']['id']) + + if oracle_db_id_uri is not '': + print("\nOracle database created.") + oracle_db_id = oracle_db_id_uri.split('/')[-1] + else: + print("\nFailed to create Oracle Database.") + raise SystemExit("\nScript ended.\n") + + manual_instance_create_request = open_sample_payload("post_oracle_create_instance.json") + manual_instance_create_request['data']['attributes']['parameters']['objectList'][0]['relationship']['database']['data'] = [oracle_db_id] + oracle_create_instance_response = requests.post(asset_service_url, headers=headers, json=manual_instance_create_request, verify=False) + + if oracle_create_instance_response.status_code is not 201: + print("\nAPI returned status code {}. Response: {}".format(oracle_create_instance_response.status_code, + oracle_create_instance_response.json())) + raise SystemExit("\nScript ended.\n") + + print ("\nRequest to create Oracle Instance has been posted.") + + oracle_instance_id_uri = verify_asset_creation(oracle_create_instance_response.json()['data']['id']) + + if oracle_instance_id_uri is not '': + print("\nOracle instance created.") + + return oracle_db_id_uri + +def discover_oracle_databases(host): + discover_databases_request = open_sample_payload("post_oracle_discover.json") + discover_databases_request['data']['attributes']['parameters']['objectList'][0]['clientName'] = host + oracle_discover_response = requests.post(asset_service_url, headers=headers, json=discover_databases_request, verify=False) + + if oracle_discover_response.status_code is not 201: + print("\nAPI returned status code {}. Response: {}".format(oracle_discover_response.status_code, + oracle_discover_response.json())) + raise SystemExit("\nScript ended.\n") + + print ("\nRequest to discover Oracle DBs on " + host +" has been posted.") + +def add_rman_catalog(catalogName, tnsName, credentialName): + rman_catalog_create_request = open_sample_payload("post_oracle_create_rman_catalog.json") + rman_catalog_create_request['data']['attributes']['parameters']['objectList'][0]['asset']['tnsName'] = tnsName + rman_catalog_create_request['data']['attributes']['parameters']['objectList'][0]['asset']['tnsName'] = rmanCatalogName + if credentialName is not '': + rman_catalog_create_request['data']['attributes']['parameters']['objectList'][0]['asset']['commonAssetAttributes']['credentials']= [{"credentialName": credentialName}] + oracle_create_rman_catalog_response = requests.post(asset_service_url, headers=headers, json=rman_catalog_create_request, verify=False) + + if oracle_create_rman_catalog_response.status_code is not 201: + print("\nAPI returned status code {}. Response: {}".format(oracle_create_rman_catalog_response.status_code, + oracle_create_rman_catalog_response.json())) + raise SystemExit("\nScript ended.\n") + + print ("\nRequest to create RMAN catalog has been posted.") + + oracle_rman_catalog_uri = verify_asset_creation(oracle_create_rman_catalog_response.json()['data']['id']) + if oracle_rman_catalog_uri is not '': + print("\nOracle RMAN Catalog created.") + return oracle_rman_catalog_uri.split('/')[-1] + else: + print("RMAN catalog creation did not respond in time, continuing without mapping the databse to the catalog") + return '' + +def add_credentials(credentialOption, credentialName): + print("Adding Credentials") + creds_create_request = open_sample_payload("post_oracle_add_creds.json") + creds_create_request['data']['attributes']['name']= credentialName + if credentialOption == "wallet": + creds_create_request['data']['attributes']['contents'] = {"useWallet": True} + elif credentialOption == "oracle" or credentialOption == "osAndOracle": + oraUser = input("Enter Oracle Username :") + oraPass = input("Enter Oracle Password :") + creds_create_request['data']['attributes']['contents'] = {"oracleUsername": oraUser, "oraclePassword": oraPass} + if credentialOption == "os" or credentialOption == "osAndOracle": + creds_create_request['data']['attributes']['contents']['osUser'] = input("Enter OS Username :") + creds_create_request['data']['attributes']['contents']['osPassword'] = input("Enter OS Password :") + creds_create_request['data']['attributes']['contents']['osDomain'] = input("Enter OS Domain :") + + oracle_create_creds_response = requests.post(credentials_url, headers=headers, json=creds_create_request, verify=False) + + if oracle_create_creds_response.status_code is not 201: + print("\nAPI returned status code {}. Response: {}".format(oracle_create_creds_response.status_code, + oracle_create_creds_response.json())) + raise SystemExit("\nScript ended.\n") + + print ("\nCreated creds for Oracle") + +def open_sample_payload(filename): + cur_dir = os.path.dirname(os.path.abspath(__file__)) + file_name = os.path.join(cur_dir, 'sample-payloads', filename) + with open(file_name, 'r') as file_handle: + return json.load(file_handle) + +def get_asset_by_id(uri): + oracle_db_get_response = requests.get(base_url + uri, headers=headers, verify=False) + + if oracle_db_get_response.status_code is not 200: + print("\nAPI returned status code: {}. Response: {}".format(oracle_db_get_response.status_code, + oracle_db_get_response.json)) + raise SystemExit("\nCound not get the Oracle database by the given ID. Script ended.\n") + + print("\nGet Oracle database API response: ", oracle_db_get_response.json()) + +def verify_asset_creation(createQueryId): + create_status_response = None + create_status = "IN_PROGRESS" + status_check_count = 0 + + while create_status == "IN_PROGRESS": + time.sleep(2) + print("\nChecking the status of the request...") + create_status_query = requests.get(asset_service_url + createQueryId, headers=headers, verify=False) + + create_status_response = create_status_query.json() + + if create_status_query.status_code is not 200: + print("\nAPI returned status code: {}. Response: {}".format(create_status_response.status_code, + create_status_response)) + raise SystemExit("\nScript ended.\n") + + create_status = create_status_response['data'][0]['attributes']['status'] + + print("\nStatus:", create_status) + + status_check_count += 1 + if status_check_count >= 10: + print("\nRequest to create the asset is still being processed. Exiting status check.") + break + + print("\nAPI Response for the Asset create request: ", create_status_response) + + if create_status == 'SUCCESS': + return create_status_response['data'][0]['attributes']['workItemResponses'][0]['links']['self']['href'] + else: + return '' + +def perform_login(base_url, username, password, domainName, domainType): + url = base_url + "/login" + req_body = {'userName': username, 'password': password, 'domainName': domainName, 'domainType': domainType} + headers = {'Content-Type': content_type} + + print("\nLogin user '{}'.".format(req_body['userName'])) + + resp = requests.post(url, headers=headers, json=req_body, verify=False) + + if resp.status_code is not 201: + print("\nLogin API failed with status code {} and {}".format(resp.status_code, resp.json())) + raise SystemExit("\nLogin failed. Please verify that the input parameters are correct and try again.\n") + + print("Login API returned response status code: {}".format(resp.status_code)) + + print("Login successful. Returning the JWT.") + + return resp.json()['token'] + +if __name__ == '__main__': + jwt = perform_login(base_url, username, password, domainName, domainType) + headers = {'Content-Type': content_type, 'Authorization': jwt} + + if addCredentials is not None: + add_credentials(addCredentials, credentialName) + + rmanCatalogId = '' + if addRMANCatalog: + rmanCatalogId = add_rman_catalog(rmanCatalogName, tnsName, credentialName) + + print("\nCreating Oracle Database...") + + oracle_id_uri = create_oracle_db(dbName, rmanCatalogId, credentialName) + + if oracle_id_uri: + print("\nGetting the Oracle DB by id: ", oracle_id_uri) + get_asset_by_id(oracle_id_uri) + + print("\nRunning Oracle discovery on " + nbserver) + discover_oracle_databases(nbserver) + + print("\nScript completed.\n") diff --git a/recipes/python/assets/create_vmware_asset_group.py b/recipes/python/assets/create_vmware_asset_group.py new file mode 100644 index 0000000..21df88f --- /dev/null +++ b/recipes/python/assets/create_vmware_asset_group.py @@ -0,0 +1,149 @@ +## The script can be run with Python 3.5 or higher version. +## The script requires 'requests' library to make the API calls. The library can be installed using the command: pip install requests. + +import argparse +import requests +import time +import login.login_api as login_api + +def get_usage(): + return ("\nThe command should be run from the parent directory of the 'assets' directory:\n" + "python -Wignore -m assets.create_vmware_asset_group -nbserver -username -password -domainName " + " -domainType -vmGroupName -vmServer [-vmGroupFilter ]\n" + "Optional argument: vmGroupFilter - Filter criteria (in OData format) to include VMs in the group. " + "If not specified, all the VMs in the given VM server are included in the group.\n") + +parser = argparse.ArgumentParser(usage = get_usage()) +parser.add_argument('-nbserver', required=True) +parser.add_argument('-username', required=True) +parser.add_argument('-password', required=True) +parser.add_argument('-domainName', required=True) +parser.add_argument('-domainType', required=True) +parser.add_argument('-vmGroupName', required=True) +parser.add_argument('-vmServer', required=True) +parser.add_argument('-vmGroupFilter', default="") +args = parser.parse_args() + +nbserver = args.nbserver +username = args.username +password = args.password +domainName = args.domainName +domainType = args.domainType +vmGroupName = args.vmGroupName +vmServer = args.vmServer +vmGroupFilter = args.vmGroupFilter + +base_url = "https://" + nbserver + "/netbackup" +asset_service_url = base_url + "/asset-service/queries/" +content_type = content_type = "application/vnd.netbackup+json;version=4.0" + +def create_vm_group(): + vm_group_create_response = requests.post(asset_service_url, headers=headers, json=vm_group_create_request, verify=False) + + if vm_group_create_response.status_code != 201: + print("\nAPI returned status code {}. Response: {}".format(vm_group_create_response.status_code, + vm_group_create_response.json())) + raise SystemExit("\nScript ended.\n") + + print ("\nRequest to create VM group has been posted.") + + vm_group_create_query_id = vm_group_create_response.json()['data']['id'] + vm_group_create_status_response = None + vm_group_create_status = "IN_PROGRESS" + status_check_count = 0 + + while vm_group_create_status == "IN_PROGRESS": + time.sleep(2) + print("\nChecking the status of the request...") + vm_group_create_status_query = requests.get(asset_service_url + vm_group_create_query_id, headers=headers, verify=False) + + vm_group_create_status_response = vm_group_create_status_query.json() + + if vm_group_create_status_query.status_code != 200: + print("\nAPI returned status code: {}. Response: {}".format(vm_group_create_status_response.status_code, + vm_group_create_status_response)) + raise SystemExit("\nScript ended.\n") + + vm_group_create_status = vm_group_create_status_response['data'][0]['attributes']['status'] + + print("\nStatus:", vm_group_create_status) + + status_check_count += 1 + if status_check_count >= 10: + print("\nRequest to create the VM group is still being processed. Exiting status check.") + break + + print("\nAPI Response for the VM group create request: ", vm_group_create_status_response) + + vm_group_id_uri = "" + if vm_group_create_status == 'SUCCESS': + print("\nVM group created.") + vm_group_id_uri = vm_group_create_status_response['data'][0]['attributes']['workItemResponses'][0]['links']['self']['href'] + + return vm_group_id_uri + + +def getAssetById(vm_group_id_uri): + vm_group_get_response = requests.get(base_url + vm_group_id_uri, headers=headers, verify=False) + + if vm_group_get_response.status_code != 200: + print("\nAPI returned status code: {}. Response: {}".format(vm_group_get_response.status_code, + vm_group_get_response.json)) + raise SystemExit("\nCound not get the VM group by the given ID. Script ended.\n") + + print("\nGet VM group API response: ", vm_group_get_response.json()) + + +print("\nExecuting the script...") + +jwt = login_api.perform_login(base_url, username, password, domainName, domainType) + +vm_group_create_request = { + "data": { + "type": "query", + "attributes": { + "queryName": "create-or-update-assets", + "workloads": [ "vmware" ], + "parameters": { + "objectList": [ + { + "correlationId": "1", + "type": "vmwareGroupAsset", + "assetGroup": { + "description": "VM group created from sample script using API", + "assetType": "vmGroup", + "filterConstraint": "", + "oDataQueryFilter": "true", + "commonAssetAttributes": { + "displayName": "", + "workloadType": "vmware", + "detection": { + "detectionMethod": "MANUAL" + } + } + } + } + ] + } + } + } +} + +asset_group_req = vm_group_create_request['data']['attributes']['parameters']['objectList'][0]['assetGroup'] +asset_group_req['commonAssetAttributes']['displayName'] = vmGroupName +asset_group_req['filterConstraint'] = vmServer +if vmGroupFilter: + asset_group_req['oDataQueryFilter'] = vmGroupFilter + + +headers = {'Content-Type': content_type, 'Authorization': jwt} + +print("\nCreating VM group...") + +vm_group_id_uri = create_vm_group() + +if vm_group_id_uri: + print("\nGetting the VM group by id: ", vm_group_id_uri) + getAssetById(vm_group_id_uri) + +print("\nScript completed.\n") diff --git a/recipes/python/assets/get_vmware_assets.py b/recipes/python/assets/get_vmware_assets.py new file mode 100644 index 0000000..5562535 --- /dev/null +++ b/recipes/python/assets/get_vmware_assets.py @@ -0,0 +1,96 @@ +## The script can be run with Python 3.5 or higher version. +## The script requires 'requests' library to make the API calls. The library can be installed using the command: pip install requests. + +import argparse +import requests +import login.login_api as login_api + +def get_usage(): + return ("\nThe command should be run from the parent directory of the 'assets' directory:\n" + "python -Wignore -m assets.get_vmware_assets -nbserver -username -password " + "-domainName -domainType [-assetType ] [-assetsFilter ]\n" + "Optional arguments:\n" + "assetType - vm or vmGroup. Default is 'vm'.\n" + "assetsFilter - OData filter to filter the returned assets (VMs or VM Groups). If not specified, returns all the assets.\n") + +parser = argparse.ArgumentParser(usage = get_usage()) +parser.add_argument('-nbserver', required=True) +parser.add_argument('-username', required=True) +parser.add_argument('-password', required=True) +parser.add_argument('-domainName', required=True) +parser.add_argument('-domainType', required=True) +parser.add_argument('-assetType', default="vm", choices=['vm', 'vmGroup']) +parser.add_argument('-assetsFilter', default="") +args = parser.parse_args() + +nbserver = args.nbserver +username = args.username +password = args.password +domainName = args.domainName +domainType = args.domainType +assetType = args.assetType +assetsFilter = args.assetsFilter + +base_url = "https://" + nbserver + "/netbackup" +vm_assets_url = base_url + "/asset-service/workloads/vmware/assets" + +default_sort = "commonAssetAttributes.displayName" + +print("\nExecuting the script...") +jwt = login_api.perform_login(base_url, username, password, domainName, domainType) + +print("\nGetting VMware {} assets...".format(assetType)) + +if assetType == "vm": + assetTypeFilter = "(assetType eq 'vm')"; + print("Printing the following VM details: VM Display Name, Instance Id, vCenter, Protection Plan Names\n") +elif assetType == "vmGroup": + assetTypeFilter = "(assetType eq 'vmGroup')"; + print("Printing the following VM group details: VM Group Name, VM Server, Filter Criteria, Protection Plan Names\n") + +if assetsFilter != "": + assetsFilter = assetsFilter + " and " + assetTypeFilter +else: + assetsFilter = assetTypeFilter + +headers = {'Authorization': jwt} + +def get_vmware_assets(): + offset = 0 + next = True + while next: + queryparams = {'page[offset]':offset, 'filter':assetsFilter, 'sort':default_sort} + assets_response = requests.get(vm_assets_url, headers=headers, params=queryparams, verify=False) + assets = assets_response.json() + + if assets_response.status_code != 200: + print("VMware Assets API returned status code: {}, response: {}\n".format(assets_response.status_code, assets_response.json())) + raise SystemExit() + + print_assets(assets['data']) + + offset += assets['meta']['pagination']['limit'] + next = assets['meta']['pagination']['hasNext'] + + if len(assets['data']) == 0: + print("No assets returned.") + +def print_assets(assets_data): + for asset in assets_data: + asset_attrs = asset['attributes'] + asset_common_attrs = asset_attrs['commonAssetAttributes'] + asset_protection_plans = [] + if "activeProtection" in asset_common_attrs : + asset_protection_list = asset_common_attrs['activeProtection']['protectionDetailsList'] + for asset_protection in asset_protection_list: + asset_protection_plans.append(asset_protection['protectionPlanName']) + + if assetType == "vm": + print(asset_common_attrs['displayName'], asset_attrs['instanceUuid'], asset_attrs['vCenter'], asset_protection_plans, sep="\t") + elif assetType == "vmGroup": + print(asset_common_attrs['displayName'], asset_attrs['filterConstraint'], asset_attrs['oDataQueryFilter'], asset_protection_plans, sep="\t") + + +get_vmware_assets() + +print("\nScript completed!\n") diff --git a/recipes/python/assets/sample-payloads/post_oracle_add_creds.json b/recipes/python/assets/sample-payloads/post_oracle_add_creds.json new file mode 100755 index 0000000..9e92a9e --- /dev/null +++ b/recipes/python/assets/sample-payloads/post_oracle_add_creds.json @@ -0,0 +1,13 @@ +{ + "data": { + "type": "credentialRequest", + "attributes": { + "name": "CredName", + "tag": null, + "category": "Oracle", + "description": "Script generated credentials", + "contents":{ + } + } + } + } \ No newline at end of file diff --git a/recipes/python/assets/sample-payloads/post_oracle_create_db.json b/recipes/python/assets/sample-payloads/post_oracle_create_db.json new file mode 100755 index 0000000..77a0e4c --- /dev/null +++ b/recipes/python/assets/sample-payloads/post_oracle_create_db.json @@ -0,0 +1,30 @@ +{ + "data": { + "type": "query", + "attributes": { + "queryName": "create-assets", + "workloads": [ + "oracle" + ], + "parameters": { + "objectList": [ + { + "correlationId": "1234", + "asset": { + "commonAssetAttributes": { + "detection": { + "detectionMethod": "MANUAL" + } + }, + "assetType": "DATABASE", + "databaseUniqueName": "sampleDatabaseUniqueName", + "databaseName": "sampleDatabaseName", + "databaseId": 234, + "databaseType": "SINGLE_INSTANCE" + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/recipes/python/assets/sample-payloads/post_oracle_create_instance.json b/recipes/python/assets/sample-payloads/post_oracle_create_instance.json new file mode 100755 index 0000000..48ab705 --- /dev/null +++ b/recipes/python/assets/sample-payloads/post_oracle_create_instance.json @@ -0,0 +1,44 @@ +{ + "data": { + "type": "query", + "attributes": { + "queryName": "create-assets", + "workloads": [ + "oracle" + ], + "parameters": { + "objectList": [ + { + "correlationId": "22", + "asset": { + "commonAssetAttributes": { + "detection": { + "detectionMethod": "MANUAL" + } + }, + "assetType": "INSTANCE", + "instanceName": "sampleInstanceName", + "clientName": "example.client.com", + "backupClientName": null, + "oracleHome": "/oracleHome", + "overrideTnsAdmin": null, + "baseHome": null, + "baseConfig": null + }, + "relationship": { + "rmanCatalog": { + "data": [ + null + ] + }, + "database": { + "data": [ + ] + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/recipes/python/assets/sample-payloads/post_oracle_create_rman_catalog.json b/recipes/python/assets/sample-payloads/post_oracle_create_rman_catalog.json new file mode 100755 index 0000000..8e43ffa --- /dev/null +++ b/recipes/python/assets/sample-payloads/post_oracle_create_rman_catalog.json @@ -0,0 +1,41 @@ +{ + "data": { + "type": "query", + "attributes": { + "queryName": "create-assets", + "workloads": [ + "oracle" + ], + "parameters": { + "objectList": [ + { + "correlationId": "1234", + "asset": { + "commonAssetAttributes": { + "detection": { + "detectionMethod": "MANUAL" + } + }, + "assetType": "RMAN_CATALOG", + "tnsName": "TNSName", + "rmanCatalogName": "CatalogName" + }, + "relationship": { + "rmanCatalog": { + "data": [ + null + ] + }, + "database": { + "data": [ + null, + null + ] + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/recipes/python/assets/sample-payloads/post_oracle_discover.json b/recipes/python/assets/sample-payloads/post_oracle_discover.json new file mode 100755 index 0000000..3f19181 --- /dev/null +++ b/recipes/python/assets/sample-payloads/post_oracle_discover.json @@ -0,0 +1,18 @@ +{ + "data": { + "type": "query", + "attributes": { + "queryName": "oracle-discover-database", + "workloads": [ + "oracle" + ], + "parameters": { + "objectList": [ + { + "clientName": "example.client.com" + } + ] + } + } + } +} \ No newline at end of file diff --git a/recipes/python/assets/sample-payloads/post_oracle_update_database_creds.json b/recipes/python/assets/sample-payloads/post_oracle_update_database_creds.json new file mode 100755 index 0000000..7c10dcf --- /dev/null +++ b/recipes/python/assets/sample-payloads/post_oracle_update_database_creds.json @@ -0,0 +1,21 @@ +{ + "data": { + "type": "query", + "attributes": { + "queryName": "oracle-validate-update-database-credentials", + "workloads": [ + "oracle" + ], + "parameters": { + "objectList": [ + { + "correlationId": "1234", + "databaseAssetId": null, + "credentialName": "SampleCredName", + "databaseUniqueName": null + } + ] + } + } + } + } \ No newline at end of file diff --git a/recipes/python/backup-restore/README.md b/recipes/python/backup-restore/README.md new file mode 100644 index 0000000..9db32a6 --- /dev/null +++ b/recipes/python/backup-restore/README.md @@ -0,0 +1,299 @@ +# NetBackup backup and restore APIs code samples of VMware agentless single, group VM and Microsoft SQL Server + +## Executing the scripts: + +Pre-requisites: +- NetBackup 8.3 or higher +- NetBackup 9.0.1 or higher for using recover from copy mssql sample +- Python 3.6 or higher +- Python modules: `requests` +- create_protection_plan_template.json template file. This template contain the required payload which is used to create the protection plan. + +Use the following commands to run the scripts. +### - Single VM backup and restore + +This single_vm_backup_restore.py script demonstrates how to backup a VM (VMware virtual machine) using a protection plan and instant access restore of VM using NetBackup APIs. + +`python single_vm_backup_restore.py --master_server --master_username --master_password --vcenter_name --vcenter_username --vcenter_password --stu_name --protection_plan_name --clientvm --restore_vmname ` + +All parameters can also be passed as command line arguments. +- `python single_vm_backup_restore.py --help` +``` +usage: single_vm_backup_restore.py [-h] [--master_server MASTER_SERVER] + [--master_server_port MASTER_SERVER_PORT] + [--master_username MASTER_USERNAME] + [--master_password MASTER_PASSWORD] + [--vcenter_name VCENTER_NAME] + [--vcenter_username VCENTER_USERNAME] + [--vcenter_password VCENTER_PASSWORD] + [--vcenter_port VCENTER_PORT] + [--stu_name STU_NAME] + [--protection_plan_name PROTECTION_PLAN_NAME] + [--clientvm CLIENTVM] + [--restore_vmname RESTORE_VMNAME] + +Single VM backup and restore scenario + +Arguments: + -h, --help show this help message and exit + --master_server MASTER_SERVER + NetBackup master server name + --master_server_port MASTER_SERVER_PORT + NetBackup master server port + --master_username MASTER_USERNAME + NetBackup master server username + --master_password MASTER_PASSWORD + NetBackup master server password + --vcenter_name VCENTER_NAME + vCenter name + --vcenter_username VCENTER_USERNAME + vCenter username + --vcenter_password VCENTER_PASSWORD + vCenter password + --vcenter_port VCENTER_PORT + vCenter port + --stu_name STU_NAME + Storage unit name + --protection_plan_name PROTECTION_PLAN_NAME + Protection plan name + --clientvm CLIENTVM Client VM name + --restore_vmname RESTORE_VMNAME + Restore VM name +``` + +Execution flow of single VM backup and restore script: +- Add vcenter to NBU master +- Discovery of Vcenter +- Create protection plan +- Subscribe asset to protection plan +- Perform immediate backup +- Verify the status of jobs +- Initiate instant access recovery +- Verify state of instant access recovery VM. +- Perform the cleanup(e.g. remove instant access VM, subscription, protection plan and vcenter) + +### - Group VM backup and restore + +This group_vm_backup_restore.py script demonstrates how to backup multiple VMs (VMware virtual machines) using a protection plan and perform bulk instant access restore of the VMs using NetBackup APIs. + +`python group_vm_backup_restore.py --master_server --master_username --master_password --vcenter_name --vcenter_username --vcenter_password --stu_name --protection_plan_name --querystring --vip_group_name --restore_vmname_prefix ` + +All parameters can also be passed as command line arguments. +- `python group_vm_backup_restore.py --help` +``` +usage: group_vm_backup_restore.py [-h] [--master_server MASTER_SERVER] + [--master_server_port MASTER_SERVER_PORT] + [--master_username MASTER_USERNAME] + [--master_password MASTER_PASSWORD] + [--vcenter_name VCENTER_NAME] + [--vcenter_username VCENTER_USERNAME] + [--vcenter_password VCENTER_PASSWORD] + [--vcenter_port VCENTER_PORT] + [--stu_name STU_NAME] + [--protection_plan_name PROTECTION_PLAN_NAME] + [--querystring QUERYSTRING] + [--vip_group_name VIP_GROUP_NAME] + [--restore_vmname_prefix RESTORE_VMNAME_PREFIX] + +Group VM backup and restore scenario + +Arguments: + -h, --help show this help message and exit + --master_server MASTER_SERVER + NetBackup master server + --master_server_port MASTER_SERVER_PORT + NetBackup port + --master_username MASTER_USERNAME + NetBackup master server user name + --master_password MASTER_PASSWORD + NetBackup master server password + --vcenter_name VCENTER_NAME + Vcenter name + --vcenter_username VCENTER_USERNAME + Vcenter username + --vcenter_password VCENTER_PASSWORD + Vcenter password + --vcenter_port VCENTER_PORT + Vcenter port + --stu_name STU_NAME + Storage unit name + --protection_plan_name PROTECTION_PLAN_NAME + Protection plan name + --querystring QUERYSTRING + Query string to create the VM intelligent group + --vip_group_name VIP_GROUP_NAME + VM intelligent group name + --restore_vmname_prefix RESTORE_VMNAME_PREFIX + Restore VM name prefix +``` +Execution flow of group VM backup and restore script: +- Add vcenter to NBU master +- Discovery of Vcenter +- Create protection plan +- Create intelligent VM group based on the querystring +- Subscribe VM group to protection plan +- Perform immediate backup +- Verify the status of jobs +- Perform bulk restore +- Perform the cleanup(e.g. remove bulk instant access VMs, subscription, protection plan, VM group and vcenter) + +### - Microsoft SQL Server Protection and Recovery workflow + +This mssql_db_backup_restore.py script demonstrates how to Protect a MSSQL Database or Instance using a protection plan, and perform a alternate recovery of a single database or all user databases using NetBackup APIs. + +`python -W ignore recipes/python/backup-restore/mssql_db_backup_restore.py --primary_server --primary_server_port 1556 --primary_username --primary_password --mssql_instance --mssql_database --mssql_server_name --mssql_use_localcreds 0 --mssql_domain --mssql_username --mssql_password --stu_name --protection_plan_name --asset_type --restore_db_prefix --restore_db_path --recover_all_user_dbs <0|1> --recover_from_copy <1|2> --copy_stu_name ` + +All parameters can also be passed as command line arguments. +- `python mssql_db_backup_restore.py -h` +``` +usage: mssql_db_backup_restore.py [-h] [--primary_server PRIMARY_SERVER] + [--primary_server_port PRIMARY_SERVER_PORT] + [--primary_username PRIMARY_USERNAME] + [--primary_password PRIMARY_PASSWORD] + [--mssql_instance MSSQL_INSTANCE] + [--mssql_database MSSQL_DATABASE] + [--mssql_server_name MSSQL_SERVER_NAME] + [--mssql_use_localcreds MSSQL_USE_LOCALCREDS] + [--mssql_domain MSSQL_DOMAIN] + [--mssql_username MSSQL_USERNAME] + [--mssql_password MSSQL_PASSWORD] + [--stu_name STU_NAME] + [--protection_plan_name PROTECTION_PLAN_NAME] + [--asset_type ASSET_TYPE] + [--restore_db_prefix RESTORE_DB_PREFIX] + [--restore_db_path RESTORE_DB_PATH] + [--recover_all_user_dbs RECOVER_ALL_USER_DBS] + [--recover_from_copy RECOVER_FROM_COPY] + [--copy_stu_name COPY_STU_NAME] +Mssql backup and alternate database recovery scenario + +Arguments: + -h, --help show this help message and exit + --primary_server PRIMARY_SERVER + NetBackup primary server name + --primary_server_port PRIMARY_SERVER_PORT + NetBackup primary server port + --primary_username PRIMARY_USERNAME + NetBackup primary server username + --primary_password PRIMARY_PASSWORD + NetBackup primary server password + --mssql_instance MSSQL_INSTANCE + MSSQL Instance name + --mssql_database MSSQL_DATABASE + MSSQL Database name + --mssql_server_name MSSQL_SERVER_NAME + MSSQL server name, this is used in the filter for GET assets API. + --mssql_use_localcreds MSSQL_USE_LOCALCREDS + MSSQL server use locally defined creds + --mssql_domain MSSQL_DOMAIN + MSSQL server domain + --mssql_username MSSQL_USERNAME + MSSQL sysadmin username + --mssql_password MSSQL_PASSWORD + MSSQL sysadmin user password + --stu_name STU_NAME Storage Unit name + --protection_plan_name PROTECTION_PLAN_NAME + Protection plan name + --asset_type ASSET_TYPE + MSSQL asset type (AvailabilityGroup, Instance, Database) + --restore_db_prefix RESTORE_DB_PREFIX + Restore database name prefix + --restore_db_path RESTORE_DB_PATH + Restore database path + --recover_all_user_dbs recover_all_user_dbs + Recover all User databases to the mssql_instance specfied with a database name prefix + --recover_from_copy RECOVER_FROM_COPY + Create a policy with a copy and then recover using the specified copy of the backup + --copy_stu_name COPY_STU_NAME + Storage Unit name for the copy + +Execution flow of a Single MSSQL database protection and alternate database recovery workflow: +- Login to Primary Server get authorization token for API use +- Add Credential with Credential Management API +- Create a MSSQL Instance Asset and associate Credential +- Asset API to find the MSSQL Instance asset id for subscription in a Protection Plan +- Create MSSQL Protection Plan and configure MSSQL database policy attribute to SkipOffline databases +- Subscribe the MSSQL Instance Asset in Protection Plan +- Fetch Asset id for database for alternate recovery +- Get recoverypoint for the database asset using its asset id +- Perform alternate database recovery of the database and report recovery job id or Perform alternate recovery of all user databases, if recover_alluserdbs is specified. +- Cleanup by removing subscription of Instance in Protection Plan, Remove Protection Plan and remove Mssql Credential + +### - Oracle Clone workflow + +This oracle_db_clone.py script demonstrates how to perform a complete database or a pluggable database clone for a previous Oracle database backup using NetBackup APIs. + +`py -W ignore recipes\python\backup-restore\oracle_db_clone.py --primary_server --primary_server_port 1556 --primary_username --primary_password --source_oracle_db --source_database_id --target_oracle_server --os_oracle_domain --os_oracle_username --os_oracle_password --clone_db_file_path --oracle_home --oracle_base_config --force_clone 1` + +`py -W ignore recipes\python\backup-restore\oracle_db_clone.py --primary_server --primary_server_port 1556 --primary_username --primary_password --source_oracle_db --source_database_id --target_oracle_server --credential_id --clone_db_file_path --oracle_home --oracle_base_config --pdb_clone 1 --avail_oracle_sid --clone_aux_file_path --force_clone 1` + +All parameters can also be passed as command line arguments. +- `python oracle_db_clone.py -h` +``` +usage: oracle_db_clone.py [-h] [--primary_server PRIMARY_SERVER] + [--primary_server_port PRIMARY_SERVER_PORT] + [--primary_username PRIMARY_USERNAME] + [--primary_password PRIMARY_PASSWORD] + [--source_oracle_db SOURCE_ORACLE_DB] + [--source_database_id SOURCE_DATABASE_ID] + [--target_oracle_server TARGET_ORACLE_SERVER] + [--os_oracle_domain OS_DOMAIN] + [--os_oracle_username OS_USERNAME] + [--os_oracle_password OS_PASSWORD] + [--clone_db_file_path DB_FILE_PATH] + [--oracle_home ORACLE_HOME] + [--oracle_base_config ORACLE_BASE_CONFIG] + [--pdb_clone PDB_CLONE] + [--avail_oracle_sid EXISTING_ORACLE_SID] + [--clone_aux_file_path AUXILIARY_FILE_PATH] + [--credential_id CREDENTIAL_ID] + [--force_clone FORCE_CLONE] + +Arguments: + -h, --help show this help message and exit + --primary_server PRIMARY_SERVER + NetBackup primary server name + --primary_server_port PRIMARY_SERVER_PORT + NetBackup primary server port + --primary_username PRIMARY_USERNAME + NetBackup primary server username + --primary_password PRIMARY_PASSWORD + NetBackup primary server password + --source_oracle_db SOURCE_ORACLE_DB + Source Oracle database name or pluggable database name, for which there is a previous backup available + --source_database_id SOURCE_DATABASE_ID + Source Oracle container database ID + --target_oracle_server TARGET_ORACLE_SERVER + Target Oracle server for clone + --os_oracle_domain OS_DOMAIN + Target operating system domain + --os_oracle_username OS_USERNAME + Target operating system username + --os_oracle_password OS_PASSWORD + Target operating system user password + --clone_db_file_path DB_FILE_PATH + File path for the cloned database + --oracle_home ORACLE_HOME + Oracle home directory on the target server + --oracle_base_config ORACLE_BASE_CONFIG + Oracle base config directory on the target server + --pdb_clone PDB_CLONE + Perform a CDB clone(0) or PDB clone(1); default: 0 + --avail_oracle_sid EXISTING_ORACLE_SID + Existing container for a PDB clone + --clone_aux_file_path AUXILIARY_FILE_PATH + File path for auxiliary instance + --credential_id CREDENTIAL_ID + Credential ID for the instance credential in Credential Management Service + --force_clone FORCE_CLONE + Force a clone operation even if pre-recovery check fails; default: 0 + +Flow of an Oracle database clone workflow: +- Pre-requisite: A backup of an Oracle database must be available +- Log in to Primary Server to get authorization token for API use +- Get asset ID for the Oracle database backup with the Asset Service API +- Get the recovery point for the specific asset ID via Recovery Point Service API +- Perform a prerecovery check for the database or pluggable database clone request +- Perform a complete database clone or a pluggable database clone and report the job ID + +See the Swagger documentation on your primary server for full API documentation https://localhost:1556/api-docs/index.html diff --git a/recipes/python/backup-restore/common.py b/recipes/python/backup-restore/common.py new file mode 100644 index 0000000..ebfade6 --- /dev/null +++ b/recipes/python/backup-restore/common.py @@ -0,0 +1,341 @@ +""" The library contain common functions which are used for both single and group VM backup and restore. """ + +## The script can be run with Python 3.6 or higher version. + +## The script requires 'requests' library to make the API calls. + +import json +import os +import sys +import time +import requests +import uuid + +headers = {"Content-Type" : "application/vnd.netbackup+json;version=4.0"} + +# Get the base NetBackup url +def get_nbu_base_url(host, port): + """ This function return NetBackup base url """ + port = f":{str(port)}" if port else '' + baseurl = f"https://{host}{port}/netbackup/" + return baseurl + +# Login to the NetBackup and get the authorization token +def get_authenticate_token(baseurl, username, password): + """ This function return token of NB master server """ + creds = {'userName':username, 'password':password} + url = f"{baseurl}login" + status_code, response_text = rest_request('POST', url, headers, data=creds) + validate_response(status_code, 201, response_text) + token = response_text['token'] + return token + +# Add vCenter credential +def add_vcenter_credential(baseurl, token, vcenter_server, vcenter_username, vcenter_password, vcenter_port, vcenter_server_type): + """ This function add the vCenter into NBU master server """ + print(f"Add the vCenter credential:[{vcenter_server}]") + headers.update({'Authorization': token}) + url = f"{baseurl}config/servers/vmservers" + payload = {'serverName':vcenter_server, 'vmType':vcenter_server_type, 'userId':vcenter_username,\ + 'password':vcenter_password, 'port':vcenter_port} + status_code, response_text = rest_request('POST', url, headers, data=payload) + validate_response(status_code, 201, response_text) + print(f"vCenter credentials added successfully:[{vcenter_server}]") + +# Get Vmware server discovery status +def get_vmware_discovery_status(baseurl, token, workload_type, vcenter_server): + """ This function return the discovery status of vCenter server """ + headers.update({'Authorization': token}) + url = f"{baseurl}admin/discovery/workloads/{workload_type}/status?"\ + f"filter=serverName eq '{vcenter_server}'" + status_code, response_text = rest_request('GET', url, headers) + validate_response(status_code, 200, response_text) + discovery_status = response_text['data'][0]['attributes']['discoveryStatus'] + return discovery_status + +# Verify Vmware server discovery status +def verify_vmware_discovery_status(baseurl, token, workload_type, vcenter_server, timeout=600): + """ This function verify the 'SUCESS' discovery status of vCenter """ + print(f"Wait for vCenter Discovery :[{vcenter_server}]") + discovery_status = '' + end_time = time.time() + timeout + while time.time() < end_time: + time.sleep(30) + discovery_status = get_vmware_discovery_status(baseurl, token, workload_type, vcenter_server) + if discovery_status == 'SUCCESS': + print(f"vCenter added successfully:[{vcenter_server}]") + break + else: + print(f"Failed to verify vCenter:[{vcenter_server}] discovery with status:[{discovery_status}]") + sys.exit(1) + print(f"vCenter discovery successful:[{vcenter_server}] with status:[{discovery_status}]") + +# Get asset info +def get_asset_info(baseurl, token, workload_type, client): + """ This function return the asset info """ + print(f"Get client asset info:[{client}]") + headers.update({'Authorization': token}) + url = f"{baseurl}asset-service/workloads/{workload_type}/assets?"\ + f"filter=commonAssetAttributes/displayName eq '{client}'" + status_code, response_text = rest_request('GET', url, headers) + validate_response(status_code, 200, response_text) + + asset_id = response_text['data'][0]['id'] + uuid = response_text['data'][0]['attributes']['instanceUuid'] + exsi_host = response_text['data'][0]['attributes']['host'] + + print(f"Client asset Id:[{asset_id}]") + print(f"Client uuid Id:[{uuid}]") + print(f"Client exsi host:[{exsi_host}]") + return asset_id, uuid, exsi_host + +# Verify the storage unit is supported for instant access +def verify_stu_instant_access_enable(baseurl, token, storage_unit_name): + """ Verify the storage unit is supported for instant access """ + headers.update({'Authorization': token}) + url = f"{baseurl}storage/storage-units/?filter=name eq '{storage_unit_name}'" + status_code, response_text = rest_request('GET', url, headers) + validate_response(status_code, 200, response_text) + is_instant_access_enable = response_text['data'][0]['attributes']['instantAccessEnabled'] + + if is_instant_access_enable: + print(f"Storage unit:[{storage_unit_name}] enabled for instant access") + else: + print(f"Storage unit:[{storage_unit_name}] disable for instant access") + raise Exception(f"Storage unit:[{storage_unit_name}] disabled for instant access") + +# Create protection plan +def create_protection_plan(baseurl, token, protection_plan_name, storage_unit_name): + """ This function create the protection plan """ + print(f"Create protection plan:[{protection_plan_name}]") + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos?meta=accessControlId" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, "create_protection_plan_template.json") + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['name'] = protection_plan_name + data['data']['attributes']['policyNamePrefix'] = protection_plan_name + data['data']['attributes']['schedules'][0]['backupStorageUnit'] = storage_unit_name + data['data']['attributes']['allowSubscriptionEdit'] = False + + status_code, response_text = rest_request('POST', url, headers, data=data) + validate_response(status_code, 201, response_text) + protection_plan_id = response_text['data']['id'] + print(f"Protection plan created successfully:[{protection_plan_id}]") + return protection_plan_id + +def run_netbackup_policy(base_url, token, policy_name): + print(f"Run policy:[{policy_name}]") + headers.update({'Authorization': token}) + url = base_url + "/admin/manual-backup/" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, "post_manual_backup.json") + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['policyName'] = policy_name + + status_code, response_text = rest_request('POST', url, headers, data=data) + validate_response(status_code, 202, response_text) + print(f"Policy run successfully:[{policy_name}]") + return response_text['data'][0]['id'] + +def delete_netbackup_policy(base_url, token, policy_name): + print(f"Delete policy:[{policy_name}]") + headers.update({'Authorization': token}) + url = base_url + f"/config/policies/{policy_name}" + status_code, response_text = rest_request('DELETE', url, headers, data='') + validate_response(status_code, 204, response_text) + print(f"Policy deleted successfully:[{policy_name}]") + +# Subscription asset to SLO +def subscription_asset_to_slo(baseurl, token, protection_plan_id, asset_id, is_vm_group=0): + """ This function subscribe the asset/group asset to protection plan """ + print(f"Subscribe client to protection plan id: [{protection_plan_id}]") + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos/{protection_plan_id}/subscriptions" + selection_type = "ASSETGROUP" if is_vm_group else "ASSET" + payload = {"data": {"type": "subscription", "attributes": \ + {"selectionType": selection_type, "selectionId": asset_id}}} + status_code, response_text = rest_request('POST', url, headers, data=payload) + validate_response(status_code, 201, response_text) + subscription_id = response_text['data']['id'] + print(f"Sucessfully subscribed asset id:[{asset_id}] to protection plan:[{protection_plan_id}]") + print(f"Subscription id is:[{subscription_id}]") + return subscription_id + +# Get subscription +def get_subscription(baseurl, token, protection_plan_id, subscription_id): + """ This function return the subscription info """ + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos/{protection_plan_id}/subscriptions/{subscription_id}" + status_code, response_text = rest_request('GET', url, headers) + validate_response(status_code, 200, response_text) + print(f"Sucessfully fetched the subscription:[{subscription_id}] details.") + +def protection_plan_backupnow(baseurl, token, protection_plan_id, asset_id): + """ This function will trigger the backup of given asset using protection plan""" + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos/{protection_plan_id}/backup-now" + selection_type = "ASSET" + payload = {"data": {"type": "backupNowRequest", + "attributes": {"selectionType": selection_type, "selectionId": asset_id}}} + + status_code, response_text = rest_request('POST', url, headers, data=payload) + validate_response(status_code, 202, response_text) + backup_job_id = response_text['data'][0]['id'] + print(f"Started backup for asset:[{asset_id}] and backup id is:[{backup_job_id}]") + return backup_job_id + +# Get job details +def get_job_details(baseurl, token, jobid): + """ This function return the job details """ + headers.update({'Authorization': token}) + url = f"{baseurl}admin/jobs/{str(jobid)}" + status_code, response_text = rest_request('GET', url, headers) + validate_response(status_code, 200, response_text) + return response_text + +# Verify given job state and status +def verify_job_state(baseurl, token, jobid, expected_state, expected_status=0, timeout=1200): + """ This function verify the job status and state with expected status and state """ + if jobid: + print(f"Wait for backup job to complete. Backup jobid:[{jobid}]") + # Verify backup job status + end_time = time.time() + timeout + while time.time() < end_time: + time.sleep(30) + response_text = get_job_details(baseurl, token, jobid) + state = response_text['data']['attributes']['state'] + if state == expected_state: + print(f"Job:[{jobid}] completed with expected state:[{expected_state}]") + status = response_text['data']['attributes']['status'] + print(f"Actual status:[{status}] and expected status:[{expected_status}]") + if status == expected_status: + print(f"Job:[{jobid}] completed with expected status:[{expected_status}]") + break + else: + print(f"Failed backup jobid:[{jobid}] with status:[{status}]") + raise Exception(f"Failed backup jobid:[{jobid}] with status:[{status}]") + else: + print(f"Failed backup jobid:[{jobid}] with state:[{state}]") + raise Exception(f"Failed backup jobid:[{jobid}] with state:[{state}]") + +# Remove protection plan +def remove_protectionplan(baseurl, token, protection_plan_id): + """ This function remove the given protection plan """ + if protection_plan_id: + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos/{protection_plan_id}" + status_code, response_text = rest_request('DELETE', url, headers) + validate_response(status_code, 204, response_text) + print(f"Successfully removed protection plan:[{protection_plan_id}]") + +# Remove vm subscription from protection plan +def remove_subscription(baseurl, token, protection_plan_id, subscription_id): + """ This function remove subscription from protection plan """ + if protection_plan_id and subscription_id: + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos/{protection_plan_id}/subscriptions/{subscription_id}" + status_code, response_text = rest_request('DELETE', url, headers) + validate_response(status_code, 204, response_text) + print(f"Successfully removed asset subscription:[{subscription_id}] "\ + f"from protection plan:[{protection_plan_id}]") + +# Remove vCenter creds from NetBackup master +def remove_vcenter_creds(baseurl, token, vcenter_name): + """ This function remove the vCenter from NBU master """ + if vcenter_name: + headers.update({'Authorization': token}) + url = f"{baseurl}config/servers/vmservers/{vcenter_name}" + status_code, response_text = rest_request('DELETE', url, headers) + validate_response(status_code, 204, response_text) + print(f"Successfully removed vCenter:[{vcenter_name}] from NBU master") + +# Execute REST API request +def rest_request(request_type, uri, header=None, **kwargs): + """ This function make call to the REST API """ + session = requests.session() + payload = kwargs.get('data') + if request_type == 'POST': + if not payload: + print("Couldn't find payload. POST request needs payload.") + sys.exit(1) + response = session.post(uri, headers=header, json=payload, verify=False) + elif request_type == 'PUT': + if not payload: + print("Couldn't find payload. PUT request needs payload.") + sys.exit(1) + response = session.put(uri, headers=header, json=payload, verify=False) + elif request_type == 'GET': + response = session.get(uri, headers=header, verify=False) + elif request_type == 'DELETE': + response = session.delete(uri, headers=header, verify=False) + else: + print(f"Invalid Rest Request type:[{request_type}].") + sys.exit(1) + + if not response.status_code: + print(f"Failed to send REST request:[{uri}]") + sys.exit(1) + + if not response.text: + response_text = '{"errorMessage":"No response text from api response"}' + else: + response_text = response.text + + try: + response_text = json.loads(response_text) + except json.decoder.JSONDecodeError: + print(f"Could not parse json from [{response_text}]") + + print(f"Successfully sent REST request:[{uri}]") + print(f"Status code:[{response.status_code}]") + print(f"Response text:[{response.text}]") + return response.status_code, response_text + +def get_recovery_points(baseurl, token, workload_type, asset_id): + """ This function return the recovery point of given asset """ + print(f"Get the recovery points for asset:[{asset_id}]") + headers.update({'Authorization': token}) + url = f"{baseurl}recovery-point-service/workloads/{workload_type}/"\ + f"recovery-points?filter=assetId eq '{asset_id}'" + status_code, response_text = rest_request('GET', url, headers) + validate_response(status_code, 200, response_text) + if (len(response_text['data'])>0): + recoverypoint_id = response_text['data'][0]['id'] + else: + recoverypoint_id = "" + return recoverypoint_id + +def get_recovery_point_copy_info(baseurl, token, workload_type, recovery_point_id): + """ This function returns the optional information for a given recovery point""" + print(f"Get the recovery point optional info:[{recovery_point_id}]") + headers.update({'Authorization': token}) + include = f"optional{workload_type.capitalize()}RecoveryPointInfo" + url = f"{baseurl}recovery-point-service/workloads/{workload_type}/"\ + f"recovery-points/{recovery_point_id}?include={include}" + status_code, response_text = rest_request('GET', url, headers) + validate_response(status_code, 200, response_text) + if (len(response_text['included'])>0): + print(response_text) + copy_info = response_text['included'][0]['attributes']['backupImageCopyInfo'] + else: + copy_info = [] + return copy_info + +# Validate the response code of the request +def validate_response(actual_status_code, expected_status_code, response_text): + """ This function validate the response status code with expected response code """ + if actual_status_code == expected_status_code: + print(f"Successfully validated the response status code:[{expected_status_code}]") + else: + print(f"Actual status code:[{actual_status_code}] not match "\ + f"with expected status code:[{expected_status_code}]") + raise Exception(f"Response Error:[{response_text['errorMessage']}] and "\ + f"details:[{response_text['errorDetails']}]") + diff --git a/recipes/python/backup-restore/group_vm_backup_restore.py b/recipes/python/backup-restore/group_vm_backup_restore.py new file mode 100644 index 0000000..7a58eba --- /dev/null +++ b/recipes/python/backup-restore/group_vm_backup_restore.py @@ -0,0 +1,192 @@ +""" This script execute the group VM backup and restore scenario. """ + +## The script can be run with Python 3.6 or higher version. + +## The script requires 'requests' library to make the API calls. + +import argparse +import common +import vm_backup +import vm_restore + +PARSER = argparse.ArgumentParser(description="Group VM backup and restore scenario") +PARSER.add_argument("--master_server", type=str, help="NetBackup master server") +PARSER.add_argument("--master_server_port", type=int, help="NetBackup port", required=False) +PARSER.add_argument("--master_username", type=str, help="NetBackup master server username") +PARSER.add_argument("--master_password", type=str, help="NetBackup master server password") +PARSER.add_argument("--vcenter_name", type=str, help="Vcenter name") +PARSER.add_argument("--vcenter_username", type=str, help="Vcenter username") +PARSER.add_argument("--vcenter_password", type=str, help="Vcenter password") +PARSER.add_argument("--vcenter_port", type=str, help="Vcenter port", required=False) +PARSER.add_argument("--stu_name", type=str, help="Storage Unit name") +PARSER.add_argument("--protection_plan_name", type=str, help="Protection plan name") +PARSER.add_argument("--querystring", type=str, help="Query string to create the VM intelligent group") +PARSER.add_argument("--vip_group_name", type=str, help="VM intelligent group name") +PARSER.add_argument("--restore_vmname_prefix", type=str, help="Restore VM name prefix") + +ARGS = PARSER.parse_args() + +headers = {"Content-Type" : "application/vnd.netbackup+json;version=4.0"} + +# Create VM intelligent group +def create_vm_intelligent_group(baseurl, token, vip_group_name, querystring, vcenter_name): + """ This function will create the intelligent VM group """ + print(f"Creating VM intelligent group {vip_group_name} with query {querystring}") + headers.update({'Authorization': token}) + payload = {} + url = f"{baseurl}asset-service/queries" + payload.update({ + "data": { + "type": "query", + "attributes": { + "queryName": "create-or-update-assets", + "workloads": ["vmware"], + "parameters": { + "objectList": [{ + "correlationId": "1", + "type": "vmwareGroupAsset", + "assetGroup": { + "commonAssetAttributes": { + "detection": { + "detectionMethod": "MANUAL" + }, + "displayName": vip_group_name, + "protectionCapabilities": { + "isProtectable": "YES", + "isRecoverable": "NO" + } + }, + "assetType": "vmGroup", + "description": "AssetGroupForMultipleVM", + "filterConstraint": vcenter_name, + "oDataQueryFilter": querystring + } + }] + } + } + } + }) + status_code, response_text = common.rest_request('POST', url, headers, data=payload) + common.validate_response(status_code, 201, response_text) + igquery_id = response_text['data']['id'] + print(f"Query created successfully: {igquery_id}") + print("Now checking its status..") + + # Check Status + url = f"{baseurl}asset-service/queries/{igquery_id}" + status = "IN_PROGRESS" + while status == "IN_PROGRESS": + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + status = response_text['data'][0]['attributes']['workItemResponses'][0]['statusDetails']['status'] + + message = response_text['data'][0]['attributes']['workItemResponses'][0]['statusDetails']['message'] + if message != "CREATED": + raise Exception(f"Response Error:[{message}]") + + print(f"VM intelligent group {vip_group_name} and query {igquery_id} created successfully") + return igquery_id + +# Get VM Intelligent Groups +def get_vm_intelligent_group(baseurl, token, workloadtype, vip_group_name): + """ This function will return the group id of given group VM """ + print("Get VM Intelligent Group ID") + headers.update({'Authorization': token}) + url = f"{baseurl}asset-service/workloads/{workloadtype}/assets?&filter=((assetType eq 'vmGroup') \ + and (commonAssetAttributes/displayName eq '{vip_group_name}'))&meta=accessControlId" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + vm_group_id = response_text['data'][0]['id'] + print(f"Successfully fetched VM Intelligent Group ID:[{vm_group_id}]") + return vm_group_id + +# Delete VM intelligent group +def remove_vm_intelligent_group(baseurl, token, vm_group_id): + """ This function will remove the intelligent VM group """ + if vm_group_id: + print(f"Deleting Intelligent VM group: [{vm_group_id}]") + headers.update({'Authorization': token}) + payload = {} + url = f"{baseurl}asset-service/queries" + payload.update({ + "data": { + "type": "query", + "attributes": { + "queryName": "delete-assets", + "workloads": ["vmware"], + "parameters": { + "objectList": [{ + "correlationId": "0", + "assetType": "vmGroup", + "id": vm_group_id + }] + } + } + } + }) + status_code, response_text = common.rest_request('POST', url, headers, data=payload) + common.validate_response(status_code, 201, response_text) + igquery_id = response_text['data']['id'] + + print(f"Deleted Intelligent VM group: [{vm_group_id}]...Now checking status...") + + url = f"{baseurl}asset-service/queries/{igquery_id}" + status = "IN_PROGRESS" + while status == "IN_PROGRESS": + status_code, response_text = common.rest_request('GET', url, headers) + data = response_text['data'][0]['attributes'] + common.validate_response(status_code, 200, response_text) + status = data['workItemResponses'][0]['statusDetails']['status'] + + message = data['workItemResponses'][0]['statusDetails']['message'] + if message != "DELETED": + raise Exception(f"Response Error:[{message}]") + + print(f"VM intelligent group {vm_group_id} and query {igquery_id} deleted successfully") + +if __name__ == '__main__': + WORKLOAD_TYPE = 'vmware' + SERVER_TYPE = 'VMWARE_VIRTUAL_CENTER_SERVER' + PROTECTION_PLAN_ID = '' + SUBSCRIPTION_ID = '' + VM_GROUP_ID = '' + MOUNT_ID_LIST_STR = '' + + BASEURL = common.get_nbu_base_url(ARGS.master_server, ARGS.master_server_port) + TOKEN = common.get_authenticate_token(BASEURL, ARGS.master_username, ARGS.master_password) + print(f"User authentication completed for master server:[{ARGS.master_server}]") + + try: + print(f"Setup the VMware environment for vCenter:[{ARGS.vcenter_name}]") + common.add_vcenter_credential(BASEURL, TOKEN, ARGS.vcenter_name, ARGS.vcenter_username, ARGS.vcenter_password, ARGS.vcenter_port, SERVER_TYPE) + common.verify_vmware_discovery_status(BASEURL, TOKEN, WORKLOAD_TYPE, ARGS.vcenter_name) + common.verify_stu_instant_access_enable(BASEURL, TOKEN, ARGS.stu_name) + PROTECTION_PLAN_ID = common.create_protection_plan(BASEURL, TOKEN, ARGS.protection_plan_name, ARGS.stu_name) + + print("Create intelligent VM group and take backup") + create_vm_intelligent_group(BASEURL, TOKEN, ARGS.vip_group_name, ARGS.querystring, ARGS.vcenter_name) + VM_GROUP_ID = get_vm_intelligent_group(BASEURL, TOKEN, WORKLOAD_TYPE, ARGS.vip_group_name) + SUBSCRIPTION_ID = common.subscription_asset_to_slo(BASEURL, TOKEN, PROTECTION_PLAN_ID, VM_GROUP_ID, is_vm_group=1) + + # Group VM backup and restore + print("Start group VM backup") + BACKUP_JOB_ID = vm_backup.perform_vm_backup(BASEURL, TOKEN, PROTECTION_PLAN_ID, VM_GROUP_ID, is_vm_group=1) + common.verify_job_state(BASEURL, TOKEN, BACKUP_JOB_ID, 'DONE') + PROTECTION_BACKUP_JOB_ID, CATALOG_BACKUP_JOB_ID = vm_backup.get_backup_job_id(BASEURL, TOKEN, BACKUP_JOB_ID, ARGS.protection_plan_name) + common.verify_job_state(BASEURL, TOKEN, PROTECTION_BACKUP_JOB_ID, 'DONE') + common.verify_job_state(BASEURL, TOKEN, CATALOG_BACKUP_JOB_ID, 'DONE') + + print("Start bulk restore") + MOUNT_ID_LIST_STR = vm_restore.perform_bulk_restore(BASEURL, TOKEN, BACKUP_JOB_ID, WORKLOAD_TYPE, ARGS.vcenter_name, ARGS.restore_vmname_prefix) + + finally: + print("Start cleanup") + # Cleanup the created protection plan + if MOUNT_ID_LIST_STR: + MOUNT_ID_LIST = MOUNT_ID_LIST_STR.split(",") + for MOUNT_ID in MOUNT_ID_LIST: + vm_restore.remove_instantaccess_vm(BASEURL, TOKEN, MOUNT_ID) + common.remove_subscription(BASEURL, TOKEN, PROTECTION_PLAN_ID, SUBSCRIPTION_ID) + remove_vm_intelligent_group(BASEURL, TOKEN, VM_GROUP_ID) + common.remove_protectionplan(BASEURL, TOKEN, PROTECTION_PLAN_ID) + common.remove_vcenter_creds(BASEURL, TOKEN, ARGS.vcenter_name) diff --git a/recipes/python/backup-restore/mssql_db_backup_restore.py b/recipes/python/backup-restore/mssql_db_backup_restore.py new file mode 100644 index 0000000..bffa007 --- /dev/null +++ b/recipes/python/backup-restore/mssql_db_backup_restore.py @@ -0,0 +1,127 @@ +""" This script execute the MSSQL Instance backup and database restore scenario. """ + +## The script can be run with Python 3.6 or higher version. + +## The script requires 'requests' library to make the API calls. +## The library can be installed using the command: pip install requests. + +import argparse +import common +import time +import workload_mssql + +PARSER = argparse.ArgumentParser(description="MSSQL Instance backup and Database restore scenario") +PARSER.add_argument("--primary_server", type=str, help="NetBackup primary server name") +PARSER.add_argument("--primary_server_port", type=int, help="NetBackup primary server port", required=False) +PARSER.add_argument("--primary_username", type=str, help="NetBackup primary server username") +PARSER.add_argument("--primary_password", type=str, help="NetBackup primary server password") +PARSER.add_argument("--mssql_instance", type=str, help="MSSQL Instance name") +PARSER.add_argument("--mssql_database", type=str, help="MSSQL Database name") +PARSER.add_argument("--mssql_server_name", type=str, help="MSSQL server name") +PARSER.add_argument("--mssql_use_localcreds", type=int, help="MSSQL server use locally defined creds", default=0) +PARSER.add_argument("--mssql_domain", type=str, help="MSSQL server domain") +PARSER.add_argument("--mssql_username", type=str, help="MSSQL sysadmin username") +PARSER.add_argument("--mssql_password", type=str, help="MSSQL sysadmin user password") +PARSER.add_argument("--stu_name", type=str, help="Storage Unit name") +PARSER.add_argument("--protection_plan_name", type=str, help="Protection plan name") +PARSER.add_argument("--asset_type", type=str, help="MSSQL asset type (AvailabilityGroup, Instance, Database)", required=False) +PARSER.add_argument("--restore_db_prefix", type=str, help="Restore database name prefix", required=True) +PARSER.add_argument("--restore_db_path", type=str, help="Restore database path", required=True) +PARSER.add_argument("--recover_all_user_dbs", type=int, help="Recover all user databases", required=False, default=0) +PARSER.add_argument("--recover_from_copy", type=int, help="Recover from the copy number specified", choices=[1,2]) +PARSER.add_argument("--copy_stu_name", type=str, help="Storage Unit name for copies", required=False) + +ARGS = PARSER.parse_args() + +if __name__ == '__main__': + WORKLOAD_TYPE = 'mssql' + PROTECTION_PLAN_ID = '' + SUBSCRIPTION_ID = '' + ASSET_TYPE = ARGS.asset_type if ARGS.asset_type else 'instance' + ALT_DB = ARGS.restore_db_prefix + + BASEURL = common.get_nbu_base_url(ARGS.primary_server, ARGS.primary_server_port) + TOKEN = common.get_authenticate_token(BASEURL, ARGS.primary_username, ARGS.primary_password) + INSTANCE_NAME = ARGS.mssql_instance + DATABASE_NAME = ARGS.mssql_database + ALT_DB_PATH = ARGS.restore_db_path + ALLDATABASES=[] + print(f"User authentication completed for primary server:[{ARGS.primary_server}]") + + try: + print(f"Setup the environment for Mssql Server:[{ARGS.mssql_server_name}]") + print(f"Setup the environment for Mssql Server:[{INSTANCE_NAME}]") + CREDENTIAL_ID, CREDENTIAL_NAME = workload_mssql.add_mssql_credential(BASEURL, TOKEN, ARGS.mssql_use_localcreds, ARGS.mssql_domain, ARGS.mssql_username, ARGS.mssql_password) + INSTANCE_ID = workload_mssql.get_mssql_asset_info(BASEURL, TOKEN, "instance", ARGS.mssql_server_name, INSTANCE_NAME) + if (INSTANCE_ID != ""): + print(f"Instance [{INSTANCE_ID}] already exists, updating credentials") + workload_mssql.update_mssql_instance_credentials(BASEURL, TOKEN, INSTANCE_ID, CREDENTIAL_NAME) + else: + print(f"Instance Asset not present, create and register it ") + workload_mssql.create_and_register_mssql_instance(BASEURL, TOKEN, INSTANCE_NAME, ARGS.mssql_server_name, CREDENTIAL_NAME); + + # you can change the subscription to a specific Instance, AvailabilityGroup or database + SUBSCRIPTION_ASSET_ID = workload_mssql.get_mssql_asset_info(BASEURL, TOKEN, ASSET_TYPE, ARGS.mssql_server_name, INSTANCE_NAME) + print(f"Asset Subscribed for protection:[{SUBSCRIPTION_ASSET_ID}]") + # find the instance assetid and start a deepdiscovery on it for databases + INSTANCE_ID = workload_mssql.get_mssql_asset_info(BASEURL, TOKEN, "instance", ARGS.mssql_server_name, INSTANCE_NAME) + + print(f"Start Discovery on the instance [{INSTANCE_NAME}] on the host [{ARGS.mssql_server_name}]") + workload_mssql.mssql_instance_deepdiscovery(BASEURL, TOKEN, INSTANCE_ID) + if(ARGS.recover_from_copy): + workload_mssql.create_netbackup_policy(BASEURL, TOKEN, ARGS.protection_plan_name, ARGS.mssql_server_name, ARGS.stu_name, ARGS.copy_stu_name) + BACKUP_JOB_ID = common.run_netbackup_policy(BASEURL, TOKEN, ARGS.protection_plan_name) + + else: + # create protection plan and subscribe the assettype to it + PROTECTION_PLAN_ID = workload_mssql.create_mssql_protection_plan(BASEURL, TOKEN, ARGS.protection_plan_name, ARGS.stu_name, "SQL_SERVER") + # update protection plan to set MSSQL policy settings to skip offline databases + workload_mssql.update_protection_plan_mssql_attr(BASEURL, TOKEN, ARGS.protection_plan_name, PROTECTION_PLAN_ID, skip_offline_db=1) + SUBSCRIPTION_ID = common.subscription_asset_to_slo(BASEURL, TOKEN, PROTECTION_PLAN_ID, SUBSCRIPTION_ASSET_ID) + + # MSSQL backup restore + print("Start MSSQL backup") + BACKUP_JOB_ID = common.protection_plan_backupnow(BASEURL, TOKEN, PROTECTION_PLAN_ID, SUBSCRIPTION_ASSET_ID) + #timeout is set at 300 seconds (5 mins to keep looking if the backups are complete) + common.verify_job_state(BASEURL, TOKEN, BACKUP_JOB_ID, 'DONE', timeout=300) + + # give nbwebservice 30 seconds to service any queued tasks, before launching recoveries + time.sleep(30) + if (ARGS.recover_all_user_dbs != 1): + # fetch the asset + RECOVERY_ASSET_ID = workload_mssql.get_mssql_asset_info(BASEURL, TOKEN, "database", ARGS.mssql_server_name, DATABASE_NAME, INSTANCE_NAME) + RECOVERY_POINT = common.get_recovery_points(BASEURL, TOKEN, WORKLOAD_TYPE, RECOVERY_ASSET_ID) + print(f"Perform Mssql single database [{DATABASE_NAME}] alternate recovery:[{ARGS.mssql_server_name}]") + ALT_DB = ALT_DB + DATABASE_NAME + RECOVERY_JOB_ID = workload_mssql.create_mssql_recovery_request(BASEURL, TOKEN, "post_mssql_singledb_alt_recovery.json", RECOVERY_POINT, RECOVERY_ASSET_ID, ARGS.mssql_username, ARGS.mssql_domain, ARGS.mssql_password, ALT_DB, ALT_DB_PATH, INSTANCE_NAME, ARGS.mssql_server_name, ARGS.recover_from_copy) + print(f"Recovery initiated , follow Job #: [{RECOVERY_JOB_ID}]") + else: + print(f"Perform alternate recovery of all databases") + #get all databases and its recovery points + ALLDATABASES = workload_mssql.get_mssql_alldbs(BASEURL, TOKEN, ARGS.mssql_server_name, INSTANCE_NAME) + print(f"Total Databases found [{len(ALLDATABASES)}]") + systemdbs_set = set(['master', 'model', 'msdb']) + for elem in ALLDATABASES: + DATABASE_NAME = elem.databasename + RECOVERY_ASSET_ID = elem.assetid + if (DATABASE_NAME in systemdbs_set): + print(f"Skipping recovery of system database [{DATABASE_NAME}]") + else: + RECOVERY_POINT = common.get_recovery_points(BASEURL, TOKEN, WORKLOAD_TYPE, RECOVERY_ASSET_ID) + if (RECOVERY_POINT != ""): + print(f"Perform Mssql database [{DATABASE_NAME}] alternate recovery:[{ARGS.mssql_server_name}]") + ALT_DB = ARGS.restore_db_prefix + DATABASE_NAME + RECOVERY_JOB_ID = workload_mssql.create_mssql_recovery_request(BASEURL, TOKEN, "post_mssql_singledb_alt_recovery.json", RECOVERY_POINT, RECOVERY_ASSET_ID, ARGS.mssql_username, ARGS.mssql_domain, ARGS.mssql_password, ALT_DB, ALT_DB_PATH, INSTANCE_NAME, ARGS.mssql_server_name, ARGS.recover_from_copy) + else: + print(f"Skipping recovery, could not find RecoveryPoint for [{DATABASE_NAME}] assetid [{RECOVERY_ASSET_ID}]") + + finally: + print("Start cleanup") + if(ARGS.recover_from_copy): + # Cleanup the created policy + common.delete_netbackup_policy(BASEURL, TOKEN, ARGS.protection_plan_name) + else: + # Cleanup the created protection plan + common.remove_subscription(BASEURL, TOKEN, PROTECTION_PLAN_ID, SUBSCRIPTION_ID) + common.remove_protectionplan(BASEURL, TOKEN, PROTECTION_PLAN_ID) + workload_mssql.remove_mssql_credential(BASEURL, TOKEN, CREDENTIAL_ID) diff --git a/recipes/python/backup-restore/oracle_db_clone.py b/recipes/python/backup-restore/oracle_db_clone.py new file mode 100644 index 0000000..66a9d71 --- /dev/null +++ b/recipes/python/backup-restore/oracle_db_clone.py @@ -0,0 +1,88 @@ +""" This script execute the Oracle Database backup and clone scenario. """ + +## The script can be run with Python 3.6 or higher version. + +## The script requires 'requests' library to make the API calls. +## The library can be installed using the command: pip install requests. + +import argparse +import common +import workload_oracle + +PARSER = argparse.ArgumentParser(description="Oracle Database clone scenario") +PARSER.add_argument("--primary_server", type=str, help="NetBackup primary server name") +PARSER.add_argument("--primary_server_port", type=int, help="NetBackup primary server port", required=False) +PARSER.add_argument("--primary_username", type=str, help="NetBackup primary server username") +PARSER.add_argument("--primary_password", type=str, help="NetBackup primary server password") +PARSER.add_argument("--source_oracle_db", type=str, help="Source client oracle database unique or pluggable database display name") +PARSER.add_argument("--source_database_id", type=str, help="Source client oracle container database id") +PARSER.add_argument("--target_oracle_server", type=str, help="Target client name") +PARSER.add_argument("--os_oracle_domain", type=str, help="Target oracle server domain") +PARSER.add_argument("--os_oracle_username", type=str, help="Target oracle username") +PARSER.add_argument("--os_oracle_password", type=str, help="Target oracle user password") +PARSER.add_argument("--clone_db_file_path", type=str, help="Clone database path", required=True) +PARSER.add_argument("--oracle_home", type=str, help="Oracle home", required=True) +PARSER.add_argument("--oracle_base_config", type=str, help="Oracle base config", required=True) +PARSER.add_argument("--pdb_clone", type=int, help="Complete CDB clone (0) or a PDB clone(1)", default=0) +PARSER.add_argument("--avail_oracle_sid", type=str, help="Target existing container for pdb clone") +PARSER.add_argument("--clone_aux_file_path", type=str, help="Auxiliary file paths") +PARSER.add_argument("--credential_id", type=str, help="Credential Id", required=False) +PARSER.add_argument("--force_clone", type=int, help="Force a clone request", default=0) + +ARGS = PARSER.parse_args() + +if __name__ == '__main__': + WORKLOAD_TYPE = 'oracle' + ASSET_TYPE = "PDB" if (ARGS.pdb_clone) else "DATABASE" + + BASEURL = common.get_nbu_base_url(ARGS.primary_server, ARGS.primary_server_port) + TOKEN = common.get_authenticate_token(BASEURL, ARGS.primary_username, ARGS.primary_password) + print(f"User authentication completed for primary server:[{ARGS.primary_server}]") + + try: + # run asset-service to get the asset id + RECOVERY_ASSET_ID = workload_oracle.get_oracle_asset_info(BASEURL, TOKEN, ASSET_TYPE, ARGS.source_oracle_db, ARGS.source_database_id) + print(f"Oracle Asset Id:[{RECOVERY_ASSET_ID}]") + # run recovery-point-service to get recovery-point-id + RECOVERY_POINT_ID = common.get_recovery_points(BASEURL, TOKEN, WORKLOAD_TYPE, RECOVERY_ASSET_ID) + print(f"Oracle Recovery Point Id:[{RECOVERY_POINT_ID}]") + + if (ARGS.pdb_clone): + preCheckURL = f"{BASEURL}recovery/workloads/oracle/scenarios/pdb-complete-clone/pre-recovery-check" + cloneURL = f"{BASEURL}recovery/workloads/oracle/scenarios/pdb-complete-clone/recover" + recovery_input_json = "post_oracle_pdb_clone.json" + data = workload_oracle.create_pdb_clone_request_payload(recovery_input_json, RECOVERY_POINT_ID, ARGS.credential_id, ARGS.target_oracle_server, + ARGS.clone_db_file_path, ARGS.oracle_home, ARGS.oracle_base_config, ARGS.avail_oracle_sid, ARGS.clone_aux_file_path) + else: + preCheckURL = f"{BASEURL}recovery/workloads/oracle/scenarios/database-complete-clone/pre-recovery-check" + cloneURL = f"{BASEURL}recovery/workloads/oracle/scenarios/database-complete-clone/recover" + recovery_input_json = "post_oracle_cdb_clone.json" + data = workload_oracle.create_cdb_clone_request_payload(recovery_input_json, RECOVERY_POINT_ID, ARGS.os_oracle_domain, ARGS.os_oracle_username, + ARGS.os_oracle_password, ARGS.target_oracle_server, ARGS.clone_db_file_path, ARGS.oracle_home, ARGS.oracle_base_config) + + # run a pre-recovery-check + print("Perform a pre-recovery-check") + status_code, response_text = workload_oracle.create_oracle_recovery_request(preCheckURL, TOKEN, data) + + common.validate_response(status_code, 200, response_text) + print(f"Pre-recovery-check response :{response_text['data']}") + preCheckFail = 0 + for _result in response_text['data']: + if (_result['attributes']['result'] != 'Passed'): + print(f"FAIL REASON: {_result['attributes']['description']}") + preCheckFail += 1 + + if ((not preCheckFail) or (ARGS.force_clone)): + # run a clone + print("Perform a database clone") + + status_code, response_text = workload_oracle.create_oracle_recovery_request(cloneURL, TOKEN, data) + + common.validate_response(status_code, 201, response_text) + CLONE_JOBID = response_text['data']['id'] + print(f"Clone initiated , follow Job # :[{CLONE_JOBID}]") + else: + print("Pre-recovery check failed. Force kick off clone using --force_clone") + + finally: + print("To cleanup the cloned instance, run dbca. Add the instance to /etc/oratab to be discovered by oracle for cleanup.") diff --git a/recipes/python/backup-restore/sample-payloads/create_mssql_policy_template.json b/recipes/python/backup-restore/sample-payloads/create_mssql_policy_template.json new file mode 100644 index 0000000..e28009b --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/create_mssql_policy_template.json @@ -0,0 +1,71 @@ +{ + "data": { + "type": "policy", + "id": "policy", + "attributes": { + "policy": { + "policyName": "policy", + "policyType": "MS-SQL-Server", + "policyAttributes": {}, + "clients": [ + { + "databaseName": "$ALL", + "hostName": "host", + "instanceName": "MSSQLSERVER" + } + ], + "schedules": [ + { + "backupCopies": { + "copies": [ + { + "failStrategy": "Continue", + "mediaOwner": "*ANY*", + "retentionLevel": 1, + "retentionPeriod": { + "value": 2, + "unit": "WEEKS" + }, + "storage": "storageUnit" + }, + { + "failStrategy": "Continue", + "mediaOwner": "*ANY*", + "retentionLevel": 1, + "retentionPeriod": { + "value": 2, + "unit": "WEEKS" + }, + "storage": "copyStorageUnit" + } + ], + "priority": -1 + }, + "backupType": "Full Backup", + "frequencySeconds": 604800, + "mediaMultiplexing": 1, + "retriesAllowedAfterRunDay": false, + "scheduleName": "Full", + "scheduleType": "Frequency", + "snapshotOnly": false, + "startWindow": [ + { + "dayOfWeek": 1, + "startSeconds": 21600, + "durationSeconds": 43200 + } + ], + "storageIsSLP": false, + "syntheticBackup": false + } + ], + + "backupSelections": { + "selections": [ + "WHOLE_DATABASE" + ] + } + } + } + } +} \ No newline at end of file diff --git a/recipes/python/backup-restore/sample-payloads/create_mssql_protection_plan_template.json b/recipes/python/backup-restore/sample-payloads/create_mssql_protection_plan_template.json new file mode 100644 index 0000000..028b45a --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/create_mssql_protection_plan_template.json @@ -0,0 +1,29 @@ +{ + "data": { + "type": "slov3", + "attributes": { + "description": "Protection Plan for MSSQL workload", + "name": "", + "schedules": [ + { + "backupStorageUnit": "", + "backupWindows": [ + { + "dayOfWeek": 1, + "startSeconds": 0, + "durationSeconds": 86400 + } + ], + "frequencySeconds": 86400, + "retention": { + "value": 2, + "unit": "WEEKS" + } + } + ], + "allowSubscriptionEdit": "False", + "workloadType": "MSSQL", + "policyNamePrefix": "" + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/create_protection_plan_template.json b/recipes/python/backup-restore/sample-payloads/create_protection_plan_template.json new file mode 100644 index 0000000..d45c294 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/create_protection_plan_template.json @@ -0,0 +1,66 @@ +{ + "data": { + "type": "slov3", + "attributes": { + "description": "Protection Plan for VMware workloads", + "name": "", + "schedules": [ + { + "backupStorageUnit": "", + "backupWindows": [ + { + "dayOfWeek": 2, + "startSeconds": 0, + "durationSeconds": 86400 + }, + { + "dayOfWeek": 3, + "startSeconds": 0, + "durationSeconds": 86400 + }, + { + "dayOfWeek": 4, + "startSeconds": 0, + "durationSeconds": 86400 + }, + { + "dayOfWeek": 5, + "startSeconds": 0, + "durationSeconds": 86400 + }, + { + "dayOfWeek": 6, + "startSeconds": 0, + "durationSeconds": 86400 + }, + { + "dayOfWeek": 7, + "startSeconds": 0, + "durationSeconds": 86400 + }, + { + "dayOfWeek": 1, + "startSeconds": 0, + "durationSeconds": 86400 + } + ], + "frequencySeconds": 86400, + "retention": { + "value": 2, + "unit": "WEEKS" + } + } + ], + "allowSubscriptionEdit": "False", + "workloadType": "VMware", + "policyNamePrefix": "", + "policyDefinition": { + "policy": { + "policyAttributes": { + "snapshotMethodArgs": "snapact=0,trantype=san:hotadd:nbd,rLim=10,rTO=0,rHz=10,enable_quiesce_failover=1,disable_quiesce=0,ignore_irvm=1,multi_org=1,skipnodisk=1,post_events=1,serverlist=,tags_unset=false,drive_selection=0" + } + } + } + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/delete_mssql_asset.json b/recipes/python/backup-restore/sample-payloads/delete_mssql_asset.json new file mode 100644 index 0000000..d562e46 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/delete_mssql_asset.json @@ -0,0 +1,18 @@ +{ + "data":{ + "type":"query", + "attributes":{ + "queryName":"delete-assets", + "workloads":["mssql"], + "parameters":{"objectList":[ + { + "correlationId":"18", + "id":"assetid-uuid", + "asset":{ + "assetType": "INSTANCE" + } + } + ]} + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/post_check_access.json b/recipes/python/backup-restore/sample-payloads/post_check_access.json new file mode 100644 index 0000000..97919ff --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_check_access.json @@ -0,0 +1,920 @@ +{ + "data": { + "type": "checkAccess", + "attributes": { + "checkAccessPairs": [ + { + "objectId": "|MANAGE|ACCESSHOSTS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|ACCESSHOSTS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|MANAGE|ACCESSHOSTS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|ACCESS-CONTROL|PRINCIPALS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|ACCESS-CONTROL|PRINCIPALS|", + "operationId": "|OPERATIONS|SECURITY|ACCESS-CONTROL|PRINCIPALS|ASSIGN-TO-ROLE|" + }, + { + "objectId": "|SECURITY|ACCESS-CONTROL|ROLES|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|SECURITY|ACCESS-CONTROL|ROLES|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|SECURITY|ACCESS-CONTROL|ROLES|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|SECURITY|ACCESS-CONTROL|ROLES|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|ACCESS-CONTROL|ROLES|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|" + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|", + "operationId": "|OPERATIONS|ASSETS|NUTANIX-AHV|PROTECT|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|", + "operationId": "|OPERATIONS|ASSETS|NUTANIX-AHV|VM|RECOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|CLUSTER|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|CLUSTER|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|CLUSTER|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|CLUSTER|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|NUTANIX-AHV|CLUSTER|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|ASSETS|CLOUD|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|ASSETS|CLOUD|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|ASSETS|CLOUD|EXPIRE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|ASSETS|CLOUD|PROTECT|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|ASSETS|CLOUD|REPLICATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|ASSETS|CLOUD|UPDATE_CONFIGURATION|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|CLOUD|", + "operationId": "|OPERATIONS|ASSETS|CLOUD|VIEW_CREDENTIALS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|RECOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|ALT_RECOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|OVERWRITE_RECOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|INSTANT_ACCESS_RECOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|PROTECT|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|CLEANUP_ASSETS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|AVAILABILITY_GROUP|DISCOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|DATABASE|DISCOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|MSSQL|", + "operationId": "|OPERATIONS|MSSQL|INSTANCE|VALIDATE_CREDENTIAL|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|", + "operationId": "|OPERATIONS|PROTECTION|PROTECTION_PLAN|SUBSCRIBE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|", + "operationId": "|OPERATIONS|ASSETS|RHV|PROTECT|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|", + "operationId": "|OPERATIONS|ASSETS|RHV|VM|RECOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|RHVMGR|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|RHVMGR|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|RHVMGR|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|RHVMGR|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|RHV|RHVMGR|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|", + "operationId": "|OPERATIONS|ASSETS|VMWARE|PROTECT|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|", + "operationId": "|OPERATIONS|ASSETS|VMWARE|VM|RECOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|", + "operationId": "|OPERATIONS|ASSETS|VMWARE|VM|INSTANT_ACCESS_RECOVER|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|ESX|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|ESX|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|ESX|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|ESX|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|ESX|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|RESTORE_ESX|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|RESTORE_ESX|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|RESTORE_ESX|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|RESTORE_ESX|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|RESTORE_ESX|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|VCENTER|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|VCENTER|", + "operationId": "|OPERATIONS|ADD|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|VCENTER|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|VCENTER|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|ASSETS|VMWARE|VCENTER|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|MANAGE|EMAIL-NOTIFICATIONS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|EMAIL-NOTIFICATIONS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|EMAIL-NOTIFICATIONS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|DATA-CLASSIFICATIONS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|CREDENTIALS|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|", + "checkAllDescendants": true + }, + { + "objectId": "|CREDENTIALS|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|CREDENTIALS|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|CREDENTIALS|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|MANAGE|HOSTS|CDP-GATEWAY|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|HOSTS|CDP-GATEWAY|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|MANAGE|HOSTS|CDP-GATEWAY|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|CREDENTIALS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|STORAGE|DISK-POOLS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|EVENTLOGS|NOTIFICATIONS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|VIEW|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|MANAGE|HOSTS|COMMENT|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|MANAGE|HOSTS|RELOAD|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|SEARCH|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|UPDATE|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|UPGRADE|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|MANAGE|HOSTS|HOSTMAPPINGS|DELETE|" + }, + { + "objectId": "|MANAGE|HOSTS|", + "operationId": "|OPERATIONS|MANAGE|HOSTS|VALIDATE|" + }, + { + "objectId": "|MANAGE|HOSTS|HOST-PROPERTIES|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|HOSTS|HOST-PROPERTIES|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|HOSTS|HOST-PROPERTIES|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|MANAGE|HOSTS|HOST-PROPERTIES|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|LICENSING|USAGE|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|PROTECTION|POLICIES|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|PROTECTION|POLICIES|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|PROTECTION|POLICIES|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|PROTECTION|POLICIES|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|PROTECTION|PROTECTION_PLAN|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|PROTECTION|PROTECTION_PLAN|", + "operationId": "|OPERATIONS|DELETE|", + "checkAllDescendants": true + }, + { + "objectId": "|PROTECTION|PROTECTION_PLAN|", + "operationId": "|OPERATIONS|UPDATE|", + "checkAllDescendants": true + }, + { + "objectId": "|PROTECTION|PROTECTION_PLAN|", + "operationId": "|OPERATIONS|PROTECTION|PROTECTION_PLAN|SUBSCRIBE|", + "checkAllDescendants": true + }, + { + "objectId": "|PROTECTION|PROTECTION_PLAN|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|PROTECTION|PROTECTION_PLAN|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|" + }, + { + "objectId": "|MANAGE|RESILIENCY|DOMAIN|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|RESILIENCY|DOMAIN|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|RESILIENCY|DOMAIN|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|RESILIENCY|DOMAIN|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|MANAGE|RESILIENCY|DOMAIN|", + "operationId": "|OPERATIONS|MANAGE|RESILIENCY|DOMAIN|DISCOVER|" + }, + { + "objectId": "|MANAGE|RETENTION-LEVELS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|RESOURCELIMITS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|RESOURCELIMITS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|MANAGE|RESOURCELIMITS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|RESOURCELIMITS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|SECURITY|KMS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|USERS|API-KEYS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|SECURITY|USERS|API-KEYS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|USERS|API-KEYS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|SECURITY|USERS|API-KEYS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|SECURITY|AUDIT-LOGS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|", + "operationId": "|OPERATIONS|SECURITY|CERTIFICATE-MANAGEMENT|NETBACKUP-CERTIFICATES|REVOKE|" + }, + { + "objectId": "|SECURITY|CREDENTIALS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|CREDENTIALS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|SECURITY|CREDENTIALS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|SECURITY|CERTIFICATE-MANAGEMENT|TOKENS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|CERTIFICATE-MANAGEMENT|TOKENS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|SECURITY|CERTIFICATE-MANAGEMENT|TOKENS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|SECURITY|SETTINGS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|SECURITY|SETTINGS|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|" + }, + { + "objectId": "|SECURITY|USERS|CERTIFICATE-MANAGEMENT|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|USERS|CERTIFICATE-MANAGEMENT|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|SECURITY|USERS|CERTIFICATE-MANAGEMENT|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|SECURITY|USERS|CERTIFICATE-MANAGEMENT|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|" + }, + { + "objectId": "|SECURITY|USERS|USER-SESSIONS|", + "operationId": "|OPERATIONS|SECURITY|USERS|USER-SESSIONS|UNLOCK|" + }, + { + "objectId": "|SECURITY|USERS|USER-SESSIONS|", + "operationId": "|OPERATIONS|SECURITY|USERS|USER-SESSIONS|VIEW-LOCKED-USERS|" + }, + { + "objectId": "|SECURITY|USERS|USER-SESSIONS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|SECURITY|USERS|USER-SESSIONS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|SECURITY|USERS|USER-SESSIONS|", + "operationId": "|OPERATIONS|SECURITY|USERS|USER-SESSIONS|CLOSE|" + }, + { + "objectId": "|SECURITY|USERS|USER-SESSIONS|", + "operationId": "|OPERATIONS|SECURITY|USERS|USER-SESSIONS|CLOSE-ALL|" + }, + { + "objectId": "|SECURITY|USERS|USER-SESSIONS|CONFIG|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|STORAGE|", + "operationId": "|OPERATIONS|VIEW|", + "checkAllDescendants": true + }, + { + "objectId": "|STORAGE|DISK-POOLS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|STORAGE|DISK-POOLS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|STORAGE|DISK-POOLS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|STORAGE|DISK-POOLS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|STORAGE|STORAGE-SERVERS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|STORAGE|STORAGE-SERVERS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|STORAGE|STORAGE-SERVERS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|STORAGE|STORAGE-SERVERS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|STORAGE|STORAGE-SERVERS|UNIVERSAL-SHARES|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|STORAGE|STORAGE-SERVERS|UNIVERSAL-SHARES|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|STORAGE|STORAGE-SERVERS|UNIVERSAL-SHARES|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|STORAGE|STORAGE-SERVERS|UNIVERSAL-SHARES|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|STORAGE|TAPE-MEDIA|SERVER-GROUPS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|STORAGE|TAPE-MEDIA|VOLUME-POOLS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|STORAGE|STORAGE-UNITS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|STORAGE|STORAGE-UNITS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|STORAGE|STORAGE-UNITS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|STORAGE|STORAGE-UNITS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|SERVERS|TRUSTED-MASTER-SERVERS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|SERVERS|TRUSTED-MASTER-SERVERS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|MANAGE|SERVERS|TRUSTED-MASTER-SERVERS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|JOBS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|JOBS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|JOBS|", + "operationId": "|OPERATIONS|DELETE|" + }, + { + "objectId": "|MANAGE|JOBS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|HOSTS|PROCESSES|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|IMAGES|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|IMAGES|", + "operationId": "|OPERATIONS|MANAGE|IMAGES|VIEW-CONTENTS|" + }, + { + "objectId": "|MANAGE|IMAGE-SHARE|CLOUD-IMAGES|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|AWS|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|AWS|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|AWS|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|AZURE|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|AZURE|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|AZURE|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|GCP|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|GCP|", + "operationId": "|OPERATIONS|ADD|" + }, + { + "objectId": "|MANAGE|SNAPSHOT-MGMT-SERVER-PLUGINS|GCP|", + "operationId": "|OPERATIONS|UPDATE|" + }, + { + "objectId": "|SECURITY|IDP|", + "operationId": "|OPERATIONS|VIEW|" + }, + { + "objectId": "|CREDENTIALS|sqlcred|", + "operationId": "|OPERATIONS|MANAGE-ACCESS|" + } + ] + } + } +} + diff --git a/recipes/python/backup-restore/sample-payloads/post_manual_backup.json b/recipes/python/backup-restore/sample-payloads/post_manual_backup.json new file mode 100644 index 0000000..b951e46 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_manual_backup.json @@ -0,0 +1,9 @@ +{ + "data": { + "attributes": { + "policyName": "policy", + "scheduleName": "Full" + }, + "type": "backupRequest" + } +} \ No newline at end of file diff --git a/recipes/python/backup-restore/sample-payloads/post_mssql_create_availabilitygroup.json b/recipes/python/backup-restore/sample-payloads/post_mssql_create_availabilitygroup.json new file mode 100644 index 0000000..bd29ae2 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_mssql_create_availabilitygroup.json @@ -0,0 +1,29 @@ +{ + "data":{ + "type":"query", + "attributes":{ + "queryName":"create-assets", + "workloads":["mssql"], + "parameters":{"objectList":[ + { + "correlationId":"1", + "asset":{ + "commonAssetAttributes": { + "displayName": "AGdemo", + "detection": { + "detectionMethod": "MANUAL" + } + }, + "assetType": "AVAILABILITY_GROUP", + "clusterName": "AGclusterdemo" + }, + "relationship": { + "instances": { + "data": ["instanceid-uuid"] + } + } + } + ]} + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/post_mssql_create_database.json b/recipes/python/backup-restore/sample-payloads/post_mssql_create_database.json new file mode 100644 index 0000000..95e4df8 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_mssql_create_database.json @@ -0,0 +1,28 @@ +{ + "data":{ + "type":"query", + "attributes":{ + "queryName":"create-assets", + "workloads":["mssql"], + "parameters":{"objectList":[ + { + "correlationId":"1", + "asset":{ + "commonAssetAttributes": { + "displayName": "testDatabase12", + "detection": { + "detectionMethod": "MANUAL" + } + }, + "assetType": "DATABASE" + }, + "relationship": { + "instances": { + "data": ["instanceid-uuid"] + } + } + } + ]} + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/post_mssql_create_instance.json b/recipes/python/backup-restore/sample-payloads/post_mssql_create_instance.json new file mode 100644 index 0000000..2222dc3 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_mssql_create_instance.json @@ -0,0 +1,28 @@ +{ + "data":{ + "type":"query", + "attributes":{ + "queryName":"create-assets", + "workloads":["mssql"], + "parameters":{"objectList":[ + { + "correlationId":"822", + "asset":{ + "commonAssetAttributes": { + "displayName": "instance33", + "detection": { + "detectionMethod": "MANUAL" + }, + "credentials": [{ + "credentialName": "sqlCreds1" + }] + }, + "clientName": "clientdemo62", + "assetType": "INSTANCE", + "managedBy": "NETBACKUP" + } + } + ]} + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/post_mssql_credential.json b/recipes/python/backup-restore/sample-payloads/post_mssql_credential.json new file mode 100644 index 0000000..8d65dca --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_mssql_credential.json @@ -0,0 +1,15 @@ +{ + "data": { + "type": "credentialRequest", + "attributes": { + "name": "", + "tag": "", + "contents": { + "domain": "", + "username": "", + "password": "" + }, + "description": "" + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/post_mssql_instance_deepdiscovery.json b/recipes/python/backup-restore/sample-payloads/post_mssql_instance_deepdiscovery.json new file mode 100644 index 0000000..390329f --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_mssql_instance_deepdiscovery.json @@ -0,0 +1,19 @@ +{ + "data": { + "type": "query", + "attributes": { + "queryName": "mssql-discover-database", + "workloads": [ + "mssql" + ], + "parameters": { + "objectList": [ + { + "correlationId": "5465", + "instanceId": "instanceuuid" + } + ] + } + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/post_mssql_singledb_alt_recovery.json b/recipes/python/backup-restore/sample-payloads/post_mssql_singledb_alt_recovery.json new file mode 100644 index 0000000..6cfa3d2 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_mssql_singledb_alt_recovery.json @@ -0,0 +1,29 @@ +{ + "data": { + "type":"recoveryRequest", + "attributes": { + "recoveryPoint":"recoverypointid-uuid", + "recoveryObject" : { + "assetId" : "assetid-uuid", + "credentials" : { + "domain" : "domain", + "userName" : "administrator", + "password" : "password" + } + }, + "recoveryOptions" : + { + "replaceDatabase" : false + }, + "alternateRecoveryOptions": + { + "databaseName": "python_test_db", + "instanceName": "SQL2K14", + "client": "client.veritas.com", + "alternateFileLocation": { + "renameAllFilesToSameLocation": "c:\\temp\\" + } + } + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/post_oracle_cdb_clone.json b/recipes/python/backup-restore/sample-payloads/post_oracle_cdb_clone.json new file mode 100644 index 0000000..fdb5bd8 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_oracle_cdb_clone.json @@ -0,0 +1,47 @@ +{ + "data": { + "type":"recoveryRequest", + "attributes": { + "recoveryPoint": "recoverypointid-uuid", + "recoveryObject": { + "instanceCredentials": { + "credentialType": "CREDENTIAL_DETAILS", + "domain": "domain", + "username": "administrator", + "password": "password" + } + }, + "alternateRecoveryOptions": { + "client": "alternateClientName", + "oracleSID": "clonedInstanceName", + "oracleHome": "C:\\oracleHome", + "oracleBaseConfig" : "C:\\oracleBase", + "databaseName": "clonedDb", + "controlFilePaths": { + "renameAllFilesToSameLocation": { + "destination" : "c:\\temp\\" + } + }, + "databaseFilePaths": { + "renameAllFilesToSameLocation": { + "destination" : "c:\\temp\\" + } + }, + "tempFilePaths": { + "renameAllFilesToSameLocation": { + "destination" : "c:\\temp\\" + } + }, + "redoFilePaths": { + "renameAllFilesToSameLocation" : { + "destination": "c:\\temp\\" + } + } + }, + "recoveryOptions": { + "streams": 4, + "createDirectories": true + } + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/post_oracle_pdb_clone.json b/recipes/python/backup-restore/sample-payloads/post_oracle_pdb_clone.json new file mode 100644 index 0000000..cab7df1 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/post_oracle_pdb_clone.json @@ -0,0 +1,47 @@ +{ + "data": { + "type":"recoveryRequest", + "attributes": { + "recoveryPoint": "recoverypointid-uuid", + "recoveryObject": { + "instanceCredentials": { + "credentialType": "CREDENTIAL_ID", + "credentialId": "credentialis-uuid" + } + }, + "alternateRecoveryOptions": { + "client": "alternateClientName", + "oracleSID": "existingSid", + "oracleHome": "C:\\oracleHome", + "oracleBaseConfig" : "C:\\oracleBase", + "databaseName": "clonepdb", + "controlFilePaths": { + "renameAllFilesToSameLocation": { + "auxiliary" : "c:\\temp\\aux" + } + }, + "databaseFilePaths": { + "renameAllFilesToSameLocation": { + "auxiliary" : "c:\\temp\\aux", + "destination" : "c:\\temp\\" + } + }, + "tempFilePaths": { + "renameAllFilesToSameLocation": { + "auxiliary" : "c:\\temp\\aux", + "destination" : "c:\\temp\\" + } + }, + "redoFilePaths": { + "renameAllFilesToSameLocation" : { + "auxiliary": "c:\\temp\\" + } + } + }, + "recoveryOptions": { + "streams": 4, + "createDirectories": true + } + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/update_mssql_instance_credentials.json b/recipes/python/backup-restore/sample-payloads/update_mssql_instance_credentials.json new file mode 100644 index 0000000..2b51109 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/update_mssql_instance_credentials.json @@ -0,0 +1,29 @@ +{ + "data": { + "type": "query", + "attributes": { + "queryName": "update-assets", + "workloads": [ + "mssql" + ], + "parameters": { + "objectList": [ + { + "correlationId": "483", + "id": "instanceasset-uuid", + "asset": { + "assetType": "INSTANCE", + "commonAssetAttributes": { + "credentials": [ + { + "credentialName": "TestCredsSQLADMIN" + } + ] + } + } + } + ] + } + } + } +} diff --git a/recipes/python/backup-restore/sample-payloads/validate_mssql_instance_credentials.json b/recipes/python/backup-restore/sample-payloads/validate_mssql_instance_credentials.json new file mode 100644 index 0000000..d844ea3 --- /dev/null +++ b/recipes/python/backup-restore/sample-payloads/validate_mssql_instance_credentials.json @@ -0,0 +1,19 @@ +{ + "data": { + "type": "query", + "attributes": { + "queryName": "validate-assets-credentials", + "workloads": [ + "mssql" + ], + "parameters": { + "objectList": [ + { + "correlationId": "1432", + "assetId": "instanceid-uuid" + } + ] + } + } + } +} diff --git a/recipes/python/backup-restore/single_vm_backup_restore.py b/recipes/python/backup-restore/single_vm_backup_restore.py new file mode 100644 index 0000000..291f611 --- /dev/null +++ b/recipes/python/backup-restore/single_vm_backup_restore.py @@ -0,0 +1,69 @@ +""" This script execute the single VM backup and restore scenario. """ + +## The script can be run with Python 3.6 or higher version. + +## The script requires 'requests' library to make the API calls. +## The library can be installed using the command: pip install requests. + +import argparse +import common +import vm_backup +import vm_restore + +PARSER = argparse.ArgumentParser(description="Single VM backup and restore scenario") +PARSER.add_argument("--master_server", type=str, help="NetBackup master server name") +PARSER.add_argument("--master_server_port", type=int, help="NetBackup master server port", required=False) +PARSER.add_argument("--master_username", type=str, help="NetBackup master server username") +PARSER.add_argument("--master_password", type=str, help="NetBackup master server password") +PARSER.add_argument("--vcenter_name", type=str, help="Vcenter name") +PARSER.add_argument("--vcenter_username", type=str, help="Vcenter username") +PARSER.add_argument("--vcenter_password", type=str, help="Vcenter password") +PARSER.add_argument("--vcenter_port", type=str, help="Vcenter port", required=False) +PARSER.add_argument("--stu_name", type=str, help="Storage Unit name") +PARSER.add_argument("--protection_plan_name", type=str, help="Protection plan name") +PARSER.add_argument("--clientvm", type=str, help="Client VM name") +PARSER.add_argument("--restore_vmname", type=str, help="Restore VM name") + +ARGS = PARSER.parse_args() + +if __name__ == '__main__': + WORKLOAD_TYPE = 'vmware' + SERVER_TYPE = 'VMWARE_VIRTUAL_CENTER_SERVER' + PROTECTION_PLAN_ID = '' + SUBSCRIPTION_ID = '' + MOUNT_ID = '' + + BASEURL = common.get_nbu_base_url(ARGS.master_server, ARGS.master_server_port) + TOKEN = common.get_authenticate_token(BASEURL, ARGS.master_username, ARGS.master_password) + print(f"User authentication completed for master server:[{ARGS.master_server}]") + + try: + print(f"Setup the VMware environment for vCenter:[{ARGS.vcenter_name}]") + common.add_vcenter_credential(BASEURL, TOKEN, ARGS.vcenter_name, ARGS.vcenter_username, ARGS.vcenter_password, ARGS.vcenter_port, SERVER_TYPE) + common.verify_vmware_discovery_status(BASEURL, TOKEN, WORKLOAD_TYPE, ARGS.vcenter_name) + common.verify_stu_instant_access_enable(BASEURL, TOKEN, ARGS.stu_name) + ASSET_ID, _, EXSI_HOST = common.get_asset_info(BASEURL, TOKEN, WORKLOAD_TYPE, ARGS.clientvm) + PROTECTION_PLAN_ID = common.create_protection_plan(BASEURL, TOKEN, ARGS.protection_plan_name, ARGS.stu_name) + SUBSCRIPTION_ID = common.subscription_asset_to_slo(BASEURL, TOKEN, PROTECTION_PLAN_ID, ASSET_ID) + + # Single VM backup and restore + print("Start single VM backup") + BACKUP_JOB_ID = vm_backup.perform_vm_backup(BASEURL, TOKEN, PROTECTION_PLAN_ID, ASSET_ID) + common.verify_job_state(BASEURL, TOKEN, BACKUP_JOB_ID, 'DONE', timeout=300) + PROTECTION_BACKUP_JOB_ID, CATALOG_BACKUP_JOB_ID = vm_backup.get_backup_job_id(BASEURL, TOKEN, BACKUP_JOB_ID, ARGS.protection_plan_name) + common.verify_job_state(BASEURL, TOKEN, PROTECTION_BACKUP_JOB_ID, 'DONE') + common.verify_job_state(BASEURL, TOKEN, CATALOG_BACKUP_JOB_ID, 'DONE') + + print(f"Perform instant access vm:[{ARGS.restore_vmname}]") + BACKUP_ID = vm_restore.get_recovery_points(BASEURL, TOKEN, WORKLOAD_TYPE, ASSET_ID) + RESOURCE_POOL = vm_restore.get_resource_pool(BASEURL, TOKEN, WORKLOAD_TYPE, ARGS.vcenter_name, EXSI_HOST) + MOUNT_ID = vm_restore.create_instant_access_vm(BASEURL, TOKEN, WORKLOAD_TYPE, BACKUP_ID, ARGS.vcenter_name, EXSI_HOST, RESOURCE_POOL, ARGS.restore_vmname) + vm_restore.verify_instant_access_vmstate(BASEURL, TOKEN, WORKLOAD_TYPE, BACKUP_ID, MOUNT_ID) + + finally: + print("Start cleanup") + # Cleanup the created protection plan + vm_restore.remove_instantaccess_vm(BASEURL, TOKEN, MOUNT_ID) + common.remove_subscription(BASEURL, TOKEN, PROTECTION_PLAN_ID, SUBSCRIPTION_ID) + common.remove_protectionplan(BASEURL, TOKEN, PROTECTION_PLAN_ID) + common.remove_vcenter_creds(BASEURL, TOKEN, ARGS.vcenter_name) diff --git a/recipes/python/backup-restore/vm_backup.py b/recipes/python/backup-restore/vm_backup.py new file mode 100644 index 0000000..f76d698 --- /dev/null +++ b/recipes/python/backup-restore/vm_backup.py @@ -0,0 +1,50 @@ +""" +The library contain functions related to NetBackup VM backup functionality. +""" + +## The script can be run with Python 3.6 or higher version. + +## The script requires 'requests' library to make the API calls. + +import common + +headers = {"Content-Type" : "application/vnd.netbackup+json;version=4.0"} + +# Perform VM backup +def perform_vm_backup(baseurl, token, protection_plan_id, asset_id, is_vm_group=0): + """ This function will trigger the backup of given asset using protection plan""" + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos/{protection_plan_id}/backup-now" + selection_type = "ASSETGROUP" if is_vm_group else "ASSET" + payload = {"data": {"type": "backupNowRequest", + "attributes": {"selectionType": selection_type, "selectionId": asset_id}}} + + status_code, response_text = common.rest_request('POST', url, headers, data=payload) + common.validate_response(status_code, 202, response_text) + backup_job_id = response_text['data'][0]['id'] + print(f"Started backup for asset:[{asset_id}] and backup id is:[{backup_job_id}]") + return backup_job_id + +# Get protection and catalog backup id +def get_backup_job_id(baseurl, token, backup_job_id, protection_plan_name): + """ This function will return the catalog and protection plan backup id""" + print("Find the protection plan and catalog backup job IDs") + protection_backup_job_id = '' + catalog_backup_job_id = '' + headers.update({'Authorization': token}) + url = f"{baseurl}admin/jobs/?filter=jobId gt {str(backup_job_id)}" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + + for jobdata in response_text['data']: + job_id = str(jobdata['id']).strip() + parent_job_id = str(jobdata['attributes']['parentJobId']).strip() + if jobdata['attributes']['policyName'].startswith(protection_plan_name) and job_id == parent_job_id: + protection_backup_job_id = parent_job_id + print(f"Protection backup Job Id:[{protection_backup_job_id}]") + + if jobdata['attributes']['policyName'].startswith('NBU_Catalog_Default') \ + and job_id == parent_job_id: + catalog_backup_job_id = parent_job_id + print(f"NBU Catalog backup Job Id:[{catalog_backup_job_id}]") + return protection_backup_job_id, catalog_backup_job_id diff --git a/recipes/python/backup-restore/vm_restore.py b/recipes/python/backup-restore/vm_restore.py new file mode 100644 index 0000000..66a6717 --- /dev/null +++ b/recipes/python/backup-restore/vm_restore.py @@ -0,0 +1,165 @@ +""" The library contain functions related to restore functionality. """ + +## The script can be run with Python 3.6 or higher version. + +## The script requires 'requests' library to make the API calls. + +import time +import common + +headers = {"Content-Type" : "application/vnd.netbackup+json;version=4.0"} + +# Perform bulk restore +def perform_bulk_restore(baseurl, token, bulk_backup_job_id, workload_type, vcenter_name, client_restore_vm_prefix): + """ This function perform the bulk restore """ + headers.update({'Authorization': token}) + jobid_list = [] + mount_id_list = [] + job_mount_dict = {} + error_msg = '' + is_error = False + url = f"{baseurl}admin/jobs/?filter=parentJobId eq {str(bulk_backup_job_id)} and "\ + f"jobId ne {str(bulk_backup_job_id)} and jobType eq 'SNAPSHOT' and "\ + f"state eq 'DONE' and (status eq 0 or status eq 1)" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + for data in response_text["data"]: + jobid_list.append(data["id"]) + print(f"Snapshot jobid list:[{(','.join(jobid_list))}]") + + for jobid in jobid_list: + mount_id = '' + url = f"{baseurl}admin/jobs/?filter=parentJobId eq {str(jobid)} and state eq 'DONE'" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + backup_id = response_text['data'][0]['attributes']['backupId'] + asset_id = response_text['data'][0]['attributes']['assetID'] + asset_name = response_text['data'][0]['attributes']['assetDisplayableName'] + print(f"Backup id for job:[{jobid}] is:[{backup_id}]") + print(f"asset id for job:[{jobid}] is:[{asset_id}]") + print(f"asset display name for job:[{jobid}] is:[{asset_name}]") + + # Get asset info + asset_id, _, exsi_host = common.get_asset_info(baseurl, token, workload_type, asset_name) + resource_pool = get_resource_pool(baseurl, token, workload_type, vcenter_name, exsi_host) + print(f"Resource pool:[{resource_pool}]") + restore_vmname = f"{client_restore_vm_prefix}_{jobid}" + print(f"Restore vm name for jobid:[{jobid}] is:[{restore_vmname}]") + try: + mount_id = create_instant_access_vm(baseurl, token, workload_type,\ + backup_id, vcenter_name, exsi_host, resource_pool, restore_vmname) + if mount_id: + mount_id_list.append(mount_id) + else: + error_msg = f"{error_msg} Unable to create the the instant VM for jobid:[{jobid}]" + is_error = True + except Exception as exc: + error_msg = f"{error_msg} Instant VM creation Exception for jobid:[{jobid}] is: {exc}" + is_error = True + + for jobid, mount_id in job_mount_dict.items(): + try: + verify_instant_access_vmstate(baseurl, token, workload_type, backup_id, mount_id) + except Exception as exc: + error_msg = f"{error_msg} Instant VM verification Exception for jobid:[{jobid}] is:{exc}" + is_error = True + + mount_id_list_str = ",".join(mount_id_list) + print(f"Mount id list:[{mount_id_list_str}]") + + if is_error: + raise Exception(error_msg) + return mount_id_list_str + +# Get vm recovery points +def get_recovery_points(baseurl, token, workload_type, asset_id): + """ This function return the recovery point of given asset """ + print(f"Get the recovery points for asset:[{asset_id}]") + headers.update({'Authorization': token}) + url = f"{baseurl}recovery-point-service/workloads/{workload_type}/"\ + f"recovery-points?filter=assetId eq '{asset_id}'" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + backup_id = response_text['data'][0]['id'] + return backup_id + +# Get resource pool of vcenter exsi +def get_resource_pool(baseurl, token, workload_type, vcenter_name, exsi_host): + """ This function return the resource pool info of vcenter and exsi host """ + headers.update({'Authorization': token}) + url = f"{baseurl}/config/workloads/{workload_type}/vcenters/"\ + f"{vcenter_name}/esxiservers/{exsi_host}/resource-pools" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + resource_pool = response_text['data']['attributes']['resourcePools'][0]['path'] + return resource_pool + +# Create instant access VM +def create_instant_access_vm(baseurl, token, workload_type, backup_id, vcenter_name, exsi_host, resource_pool, client_restore_name): + """ This function create the instant access VM """ + print(f"Instant restore is initiated:[{client_restore_name}]") + headers.update({'Authorization': token}) + payload = { + "data": { + "type": "instantAccessVmV3", + "attributes": { + "backupId": backup_id, + "copyNumber": 1, + "vCenter": vcenter_name, + "esxiHost": exsi_host, + "resourcePoolOrVapp": resource_pool, + "vmName": client_restore_name, + "powerOn": "True", + "removeEthCards": "False", + "retention": { + "value": 30, + "unit": "DAYS" + }, + }, + } + } + url = f"{baseurl}recovery/workloads/{workload_type}/instant-access-vms" + status_code, response_text = common.rest_request('POST', url, headers, data=payload) + common.validate_response(status_code, 201, response_text) + mount_id = response_text['data']['id'] + return mount_id + +# Get instant access VM state +def get_instantaccess_vmstate(baseurl, token, workload_type, mount_id): + """ This function return state of instant access VM """ + headers.update({'Authorization': token}) + url = f"{baseurl}recovery/workloads/{workload_type}/instant-access-vms/{mount_id}" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + status = response_text['data']['attributes']['status'] + return status + +# Verify instant access VM state +def verify_instant_access_vmstate(baseurl, token, workload_type, backup_id, mount_id, timeout=600): + """ This function verify the 'ACTIVE' state of access VM """ + # Get Vmware server discovery status + print("Verify the instant access VM state") + inst_access_vmstatus = '' + end_time = time.time() + timeout + while time.time() < end_time: + time.sleep(20) + inst_access_vmstatus = get_instantaccess_vmstate(baseurl, token, workload_type, mount_id) + if inst_access_vmstatus == 'ACTIVE': + print("Restore Successful") + break + else: + print(f"Restore is failed of backup:[{backup_id}] with status:[{inst_access_vmstatus}]") + raise Exception(f"Restore is failed of backup:[{backup_id}] with status:[{inst_access_vmstatus}]") + + print(f"Verified instant access restore status:[{inst_access_vmstatus}]") + return mount_id + +# Remove instant access VM +def remove_instantaccess_vm(baseurl, token, mount_id): + """ This function remove the instant access VM""" + if mount_id: + headers.update({'Authorization': token}) + url = f"{baseurl}recovery/workloads/vmware/instant-access-vms/{mount_id}" + status_code, response_text = common.rest_request('DELETE', url, headers) + common.validate_response(status_code, 204, response_text) + print(f"Successfully removed instant access vm:[{mount_id}]") diff --git a/recipes/python/backup-restore/workload_mssql.py b/recipes/python/backup-restore/workload_mssql.py new file mode 100644 index 0000000..4887188 --- /dev/null +++ b/recipes/python/backup-restore/workload_mssql.py @@ -0,0 +1,303 @@ +""" +The library contain functions related to NetBackup MSSQL workload +""" + +## The script can be run with Python 3.6 or higher version. + + +import common +import json +import os +import uuid +import datetime + +class MssqlDatabase: + def __init__(self, databasename, assetid): + self.databasename = databasename + self.assetid = assetid + +SqlDatabases=[] +headers = {"Content-Type" : "application/vnd.netbackup+json;version=4.0"} + +# Get mssql_asset info +def get_mssql_asset_info(baseurl, token, asset_type, host_name, display_name, instance_name='MSSQLSERVER'): + """ This function return the asset info """ + print(f"Get client asset info for MSSQL type :[asset_type]") + headers.update({'Authorization': token}) + if (asset_type == "database"): + url = f"{baseurl}asset-service/workloads/mssql/assets?"\ + f"filter=assetType eq '{asset_type}' and displayName eq '{display_name}' and clientName eq '{host_name}' and instanceName eq '{instance_name}'" + else: + url = f"{baseurl}asset-service/workloads/mssql/assets?"\ + f"filter=assetType eq '{asset_type}' and displayName eq '{display_name}' and clientName eq '{host_name}'" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + + asset_id = response_text['data'][0]['id'] + + print(f"Client asset Id:[{asset_id}]") + return asset_id + +# Get mssql_alldbs +def get_mssql_alldbs(baseurl, token, host_name, instance_name='MSSQLSERVER'): + """ This function returns all database assets """ + print(f"Get all databases asset info for MSSQL server [{host_name}]") + headers.update({'Authorization': token}) + url = f"{baseurl}asset-service/workloads/mssql/assets?"\ + f"filter=assetType eq 'database' and clientName eq '{host_name}' and instanceName eq '{instance_name}'" + getNext = True + while getNext: + status_code, response_text = common.rest_request('GET', url, headers) + print(f"status code is [{status_code}]") + if (status_code == 200): + limit = len(response_text['data']) + for i in range(0,limit,1): + attr = response_text['data'][i]['attributes'] + assetid = response_text['data'][i]['id'] + dbname = response_text['data'][i]['attributes']['commonAssetAttributes']['displayName'] + lastbackup = "" + if ("backupDetails" in attr): + if ("lastFullBackup" in attr['backupDetails']): + lastbackup = response_text['data'][i]['attributes']['backupDetails']['lastFullBackup'] + if (lastbackup): + db=MssqlDatabase(dbname,assetid) + SqlDatabases.append(db) + link = response_text['links'] + if ("next" in link): + if ("href" in link['next']): + url = response_text['links']['next']['href'] + getNext = response_text['meta']['pagination']['hasNext'] + + return SqlDatabases + +# Create protection plan +def create_mssql_protection_plan(baseurl, token, protection_plan_name, storage_unit_name, workload_type): + """ This function will create the version 3 protection plan """ + print(f"Create protection plan:[{protection_plan_name}]") + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos?meta=accessControlId" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, "create_mssql_protection_plan_template.json") + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['description'] = "Protection Plan for MSSQL Workload" + data['data']['attributes']['name'] = protection_plan_name + data['data']['attributes']['policyNamePrefix'] = protection_plan_name + data['data']['attributes']['workloadType'] = workload_type + data['data']['attributes']['schedules'][0]['backupStorageUnit'] = storage_unit_name + #adjust the dayOfWeek for the current day, and startSeconds and duration in seconds for an hour + dow = datetime.datetime.today().isoweekday() + now = datetime.datetime.now() + midnight = now.replace(hour=0, minute=0, second=0, microsecond=0) + seconds = (now - midnight).seconds + if (dow == 7): + dow = 0 + else: + dow = dow + 1 + data['data']['attributes']['schedules'][0]['backupWindows'][0]['dayOfWeek'] = dow + seconds = seconds - 600 + data['data']['attributes']['schedules'][0]['backupWindows'][0]['startSeconds'] = seconds + seconds = 3600 + data['data']['attributes']['schedules'][0]['backupWindows'][0]['durationSeconds'] = seconds + + #FULL schedule type with 4 week retention and a frequency of everyday + data['data']['attributes']['schedules'][0]['scheduleType'] = "FULL" + data['data']['attributes']['schedules'][0]['frequencySeconds'] = 86400 + data['data']['attributes']['schedules'][0]['retention']['value'] = 4 + data['data']['attributes']['schedules'][0]['retention']['unit'] = "WEEKS" + + status_code, response_text = common.rest_request('POST', url, headers, data=data) + common.validate_response(status_code, 201, response_text) + protection_plan_id = response_text['data']['id'] + print(f"Protection plan created successfully:[{protection_plan_id}]") + return protection_plan_id + +def create_netbackup_policy(base_url, token, policy_name, client, storage_unit_name, copy_storage_unit_name): + print(f"Create policy:[{policy_name}]") + headers.update({'Authorization': token}) + url = base_url + "/config/policies/" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, "create_mssql_policy_template.json") + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['policy']['policyName'] = policy_name + data['data']['id'] = policy_name + data['data']['attributes']['policy']['clients'][0]['hostName'] = client + data['data']['attributes']['policy']['policyAttributes']['storage'] = storage_unit_name + data['data']['attributes']['policy']['schedules'][0]['backupCopies']['copies'][0]['storage'] = storage_unit_name + data['data']['attributes']['policy']['schedules'][0]['backupCopies']['copies'][1]['storage'] = copy_storage_unit_name + + status_code, response_text = common.rest_request('POST', url, headers, data=data) + common.validate_response(status_code, 204, response_text) + print(f"Policy created successfully:[{policy_name}]") + +# Update SLO Mssql attributes +def update_protection_plan_mssql_attr(baseurl, token, protection_plan_name, protection_plan_id, skip_offline_db=0): + """ Update SLO with mssql attributes """ + headers.update({'Authorization': token}) + url = f"{baseurl}servicecatalog/slos/{protection_plan_id}" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + response_text['data']['attributes']['policyDefinition']['policy']['policyAttributes']['databaseOptions']['skipUnavailableDatabases'] = True + response_text['data']['attributes']['policyDefinition']['policy']['policyAttributes']['databaseOptions']['parallelBackupOps'] = 10 + response_text['data']['attributes']['policyDefinition']['policy']['schedules'][0]['storageIsSLP'] = False + payload = response_text + status_code, response_text2 = common.rest_request('PUT', url, headers, data=payload) + common.validate_response(status_code, 204, response_text2) + +def mssql_instance_deepdiscovery(baseurl, token, mssql_instance_id): + """ This function will invoke deep discovery for databases on the instance""" + headers.update({'Authorization': token}) + url = f"{baseurl}/asset-service/queries" + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, 'post_mssql_instance_deepdiscovery.json') + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['parameters']['objectList'][0]['instanceId'] = mssql_instance_id + + print(f"MSSQL deep discovery for databases ") + status_code, response_text = common.rest_request('POST', url, headers, data=data) + common.validate_response(status_code, 201, response_text) + print(f"MSSQL deep discovery for databases started successfully") + +def add_mssql_credential(baseurl, token, mssql_use_localcreds, mssql_domain, mssql_username, mssql_password): + """ This function add the MSSQL into NBU primary server """ + print(f"Add MSSQL credential") + x = uuid.uuid1() + headers.update({'Authorization': token}) + url = f"{baseurl}/config/credentials" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, 'post_mssql_credential.json') + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['id'] = str(x) + data['data']['type'] = "credentialRequest" + data['data']['attributes']['name'] = "pyname" + data['data']['attributes']['tag'] = "pytag" + if mssql_use_localcreds: + data['data']['attributes']['contents']['useLocalCredentials'] = True + else: + data['data']['attributes']['contents']['domain'] = mssql_domain + data['data']['attributes']['contents']['username'] = mssql_username + data['data']['attributes']['contents']['password'] = mssql_password + data['data']['attributes']['description'] = "pydesc" + + status_code, response_text = common.rest_request('POST', url, headers, data=data) + common.validate_response(status_code, 201, response_text) + print(f"MSSQL credentials added successfully") + return response_text['data']['id'], response_text['data']['attributes']['name'] + +# update INSTANCE asset with credentials +def update_mssql_instance_credentials(baseurl, token, instance_id, credential_name): + """ This function updates MSSQL INSTANCE asset with the credential""" + print(f"Update MSSQL instance credentials") + headers.update({'Authorization': token}) + url = f"{baseurl}/asset-service/queries" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, 'update_mssql_instance_credentials.json') + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['parameters']['objectList'][0]['id'] = instance_id + data['data']['attributes']['parameters']['objectList'][0]['asset']['commonAssetAttributes']['credentials'][0]['credentialName'] = credential_name + + status_code, response_text = common.rest_request('POST', url, headers, data=data) + common.validate_response(status_code, 201, response_text) + print(f"MSSQL credentials updated successfully") + +# validate assigned credential to the instance-asset is valid +def validate_mssql_credential(baseurl, token, instance_id): + """ This function validates MSSQL credential assigned to the INSTANCE asset """ + print(f"Validate MSSQL credential") + headers.update({'Authorization': token}) + url = f"{baseurl}/asset-service/queries" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, 'validate_mssql_instance_credentials.json') + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['parameters']['objectList'][0]['assetId'] = instance_id + + status_code, response_text = common.rest_request('POST', url, headers, data=data) + common.validate_response(status_code, 201, response_text) + print(f"MSSQL credentials validated successfully") + +# remove mssql credential +def remove_mssql_credential(baseurl, token, credential_id): + """ This function is for mssql remove credential request""" + print(f"remove mssql credential:[{credential_id}]") + headers.update({'Authorization': token}) + url = f"{baseurl}/config/credentials/{credential_id}" + + status_code, response_text = common.rest_request('DELETE', url, headers) + common.validate_response(status_code, 204, response_text) + +# Create mssql instance asset and register it +def create_and_register_mssql_instance(baseurl, token, instance_name, server_name, credential_name): + """ This function is for mssql create instance and register request""" + print(f"create mssql instance and register request:[{instance_name}]") + headers.update({'Authorization': token}) + url = f"{baseurl}asset-service/queries" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, 'post_mssql_create_instance.json') + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['parameters']['objectList'][0]['asset']['commonAssetAttributes']['displayName'] = instance_name + data['data']['attributes']['parameters']['objectList'][0]['asset']['commonAssetAttributes']['credentials'][0]['credentialName'] = credential_name + data['data']['attributes']['parameters']['objectList'][0]['asset']['clientName'] = server_name + + status_code, response_text = common.rest_request('POST', url, headers, data=data) + common.validate_response(status_code, 201, response_text) + get_query_url = response_text['data']['links']['self']['href'] + url = f"{baseurl}{get_query_url}" + + status_code, response_text = common.rest_request('GET', url, headers) + +# Create mssql recovery request +def create_mssql_recovery_request(baseurl, token, mssql_recovery_input, rp_id, asset_id, mssql_sysadm_user, mssql_sysadm_domain, mssql_sysadm_pwd, mssql_alt_db_name, mssql_alt_db_path, mssql_instance_name, mssql_server_name, recover_from_copy): + """ This function is for mssql recovery request""" + print(f"create mssql recovery request:[{mssql_recovery_input}]") + headers.update({'Authorization': token}) + url = f"{baseurl}/recovery/workloads/mssql/scenarios/database-complete-recovery/recover" + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, mssql_recovery_input) + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['recoveryPoint'] = rp_id + data['data']['attributes']['recoveryObject']['assetId'] = asset_id + data['data']['attributes']['recoveryObject']['credentials']['domain'] = mssql_sysadm_domain + data['data']['attributes']['recoveryObject']['credentials']['userName'] = mssql_sysadm_user + data['data']['attributes']['recoveryObject']['credentials']['password'] = mssql_sysadm_pwd + data['data']['attributes']['alternateRecoveryOptions']['databaseName'] = mssql_alt_db_name + data['data']['attributes']['alternateRecoveryOptions']['instanceName'] = mssql_instance_name + data['data']['attributes']['alternateRecoveryOptions']['client'] = mssql_server_name + data['data']['attributes']['alternateRecoveryOptions']['alternateFileLocation']['renameAllFilesToSameLocation'] = mssql_alt_db_path + if(recover_from_copy): + info = common.get_recovery_point_copy_info(baseurl, token, 'mssql', rp_id) + if(len(info)>0): + data['data']['attributes']['recoveryOptions']['mssqlRecoveryCopyInfo'] = {} + data['data']['attributes']['recoveryOptions']['mssqlRecoveryCopyInfo']['fullRecoveryCollection'] = [{}] + for copy in info[0]['copies']: + if(copy['copyNumber'] == recover_from_copy): + copy['storage'].pop('sType',None) + data['data']['attributes']['recoveryOptions']['mssqlRecoveryCopyInfo']['fullRecoveryCollection'][0]['backupId'] = info[0]['backupId'] + data['data']['attributes']['recoveryOptions']['mssqlRecoveryCopyInfo']['fullRecoveryCollection'][0]['storage'] = copy['storage'] + status_code, response_text = common.rest_request('POST', url, headers, data=data) + common.validate_response(status_code, 201, response_text) + recovery_job_id = response_text['data']['id'] + print(f"MSSQL Recovery Request started successfully jobid :[{recovery_job_id}]") + return recovery_job_id + diff --git a/recipes/python/backup-restore/workload_oracle.py b/recipes/python/backup-restore/workload_oracle.py new file mode 100644 index 0000000..3b2966e --- /dev/null +++ b/recipes/python/backup-restore/workload_oracle.py @@ -0,0 +1,93 @@ +""" +The library contain functions related to NetBackup Oracle workload +""" + +## The script can be run with Python 3.6 or higher version. + +import common +import json +import os + +headers = {"Content-Type" : "application/vnd.netbackup+json;version=4.0"} + +# Get oracle_asset info +def get_oracle_asset_info(baseurl, token, asset_type, display_name, database_id): + """ This function return the asset info """ + print(f"Get client asset info for Oracle type :[asset_type]") + headers.update({'Authorization': token}) + if (asset_type == "DATABASE"): + url = f"{baseurl}asset-service/workloads/oracle/assets?"\ + f"filter=assetType eq '{asset_type}' and databaseUniqueName eq '{display_name}' and databaseId eq '{database_id}'" + else: + url = f"{baseurl}asset-service/workloads/oracle/assets?"\ + f"filter=assetType eq '{asset_type}' and displayName eq '{display_name}' and containerDatabaseId eq '{database_id}'" + status_code, response_text = common.rest_request('GET', url, headers) + common.validate_response(status_code, 200, response_text) + + asset_id = response_text['data'][0]['id'] + + print(f"Client asset Id:[{asset_id}]") + return asset_id + +# Create cdb clone request payload +def create_cdb_clone_request_payload(oracle_recovery_input, rp_id, os_domain, os_username, os_password, alt_client_name, clone_db_file_path, oracle_home, oracle_base_config): + """ This function return the cdb clone request payload """ + print(f"create oracle recovery request:[{oracle_recovery_input}]") + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, oracle_recovery_input) + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['recoveryPoint'] = rp_id + data['data']['attributes']['recoveryObject']['instanceCredentials']['domain'] = os_domain + data['data']['attributes']['recoveryObject']['instanceCredentials']['username'] = os_username + data['data']['attributes']['recoveryObject']['instanceCredentials']['password'] = os_password + data['data']['attributes']['recoveryObject']['instanceCredentials']['credentialType'] = 'CREDENTIAL_DETAILS' + data['data']['attributes']['alternateRecoveryOptions']['client'] = alt_client_name + data['data']['attributes']['alternateRecoveryOptions']['oracleSID'] = 'clonedinstance' + data['data']['attributes']['alternateRecoveryOptions']['databaseName'] = 'CLONEDDB' + data['data']['attributes']['alternateRecoveryOptions']['oracleHome'] = oracle_home + data['data']['attributes']['alternateRecoveryOptions']['oracleBaseConfig'] = oracle_base_config + data['data']['attributes']['alternateRecoveryOptions']['controlFilePaths']['renameAllFilesToSameLocation']['destination'] = clone_db_file_path + data['data']['attributes']['alternateRecoveryOptions']['databaseFilePaths']['renameAllFilesToSameLocation']['destination'] = clone_db_file_path + data['data']['attributes']['alternateRecoveryOptions']['tempFilePaths']['renameAllFilesToSameLocation']['destination'] = clone_db_file_path + data['data']['attributes']['alternateRecoveryOptions']['redoFilePaths']['renameAllFilesToSameLocation']['destination'] = clone_db_file_path + + return data + +# Create pdb clone request payload +def create_pdb_clone_request_payload(oracle_recovery_input, rp_id, credential_id, alt_client_name, clone_db_file_path, oracle_home, oracle_base_config, avail_oracle_sid, clone_aux_file_path): + """ This function return the pdb clone request payload """ + print(f"create oracle recovery request:[{oracle_recovery_input}]") + + cur_dir = os.path.dirname(os.path.abspath(__file__)) + cur_dir = cur_dir + os.sep + "sample-payloads" + os.sep + file_name = os.path.join(cur_dir, oracle_recovery_input) + with open(file_name, 'r') as file_handle: + data = json.load(file_handle) + data['data']['attributes']['recoveryPoint'] = rp_id + data['data']['attributes']['recoveryObject']['instanceCredentials']['credentialId'] = credential_id + data['data']['attributes']['recoveryObject']['instanceCredentials']['credentialType'] = 'CREDENTIAL_ID' + data['data']['attributes']['alternateRecoveryOptions']['client'] = alt_client_name + data['data']['attributes']['alternateRecoveryOptions']['oracleSID'] = avail_oracle_sid + data['data']['attributes']['alternateRecoveryOptions']['databaseName'] = 'CLONEPDB' + data['data']['attributes']['alternateRecoveryOptions']['oracleHome'] = oracle_home + data['data']['attributes']['alternateRecoveryOptions']['oracleBaseConfig'] = oracle_base_config + data['data']['attributes']['alternateRecoveryOptions']['controlFilePaths']['renameAllFilesToSameLocation']['auxiliary'] = clone_aux_file_path + data['data']['attributes']['alternateRecoveryOptions']['databaseFilePaths']['renameAllFilesToSameLocation']['auxiliary'] = clone_aux_file_path + data['data']['attributes']['alternateRecoveryOptions']['databaseFilePaths']['renameAllFilesToSameLocation']['destination'] = clone_db_file_path + data['data']['attributes']['alternateRecoveryOptions']['tempFilePaths']['renameAllFilesToSameLocation']['auxiliary'] = clone_aux_file_path + data['data']['attributes']['alternateRecoveryOptions']['tempFilePaths']['renameAllFilesToSameLocation']['destination'] = clone_db_file_path + data['data']['attributes']['alternateRecoveryOptions']['redoFilePaths']['renameAllFilesToSameLocation']['auxiliary'] = clone_aux_file_path + + return data + +# Submit oracle recovery request +def create_oracle_recovery_request(baseurl, token, data): + """ This function submits a clone request """ + headers.update({'Authorization': token}) + + status_code, response_text = common.rest_request('POST', baseurl, headers, data=data) + + return status_code, response_text diff --git a/recipes/python/config/README.md b/recipes/python/config/README.md new file mode 100644 index 0000000..bcce2bb --- /dev/null +++ b/recipes/python/config/README.md @@ -0,0 +1,21 @@ +### NetBackup Hosts Configuration Management API Code Samples + +This directory contains Python scripts demonstrating the use of NetBackup Hosts Configuration Management APIs to update exclude list on a NetBackup host. + +#### Disclaimer + +These samples are provided only for reference and not meant for production use. + +#### Executing the script + +Pre-requisites: +- NetBackup 8.2 or higher +- Python 3.5 or higher +- Python modules: `requests`. + + +Use the following command to run the script. The command should be run from the parent directory of this 'config' directory. + +`python -W ignore -m config.hosts_exclude_list -hostName -nbmaster -username -password [-domainName ] [-domainType ]` + +`Note: hostName is the name of the NetBackup host to set the exclude configuration. The exclude list is specified in the config/exclude_list file.` diff --git a/recipes/python/config/exclude_list.py b/recipes/python/config/exclude_list.py new file mode 100644 index 0000000..2fecb89 --- /dev/null +++ b/recipes/python/config/exclude_list.py @@ -0,0 +1,8 @@ + +EXCLUDE_LIST = ("C:\\Program Files\\Veritas\\NetBackup\\bin\\*.lock", + "C:\\Program Files\\Veritas\\NetBackup\\bin\\bprd.d\\*.lock", + "C:\\Program Files\\Veritas\\NetBackup\\bin\\bpsched.d\\*.lock", + "C:\\Program Files\\Veritas\\Volmgr\\misc\\*", + "C:\\Program Files\\Veritas\\NetBackupDB\\data\\*", + "D:\\privatedata\\exclude", + "D:\\tempdata\\exclude") diff --git a/recipes/python/config/hosts_api.py b/recipes/python/config/hosts_api.py new file mode 100644 index 0000000..e667cca --- /dev/null +++ b/recipes/python/config/hosts_api.py @@ -0,0 +1,50 @@ +import requests + +config_hosts_url = "/config/hosts/" +content_type_header = "application/vnd.netbackup+json;version=3.0" +accept_header = "application/vnd.netbackup+json;version=3.0" + +def get_host_uuid(base_url, jwt, host_name): + headers = {'Accept': accept_header, 'Authorization': jwt} + queryparams = {'filter':"hostName eq '{}'".format(host_name)} + print("\nCalling Config Hosts API to get the uuid of the host {}.".format(host_name)) + response = requests.get(base_url + config_hosts_url, headers=headers, params=queryparams, verify=False) + + if response.status_code != 200: + print("\nGET Host API failed with status code {} and {}".format(response.status_code, response.json())) + raise SystemExit("\n\n") + + print("GET Hosts API returned status: {}".format(response.status_code)) + host_uuid = response.json()['hosts'][0]['uuid'] + print("Returning the host uuid: " + host_uuid) + + return host_uuid + +def get_host_configuration(base_url, jwt, host_uuid, config_name): + headers = {'Accept': accept_header, 'Authorization': jwt} + print("\nCalling Config Hosts API to get the '{}' configuration setting on the host '{}'.".format(config_name, host_uuid)) + + host_config_url = base_url + config_hosts_url + host_uuid + "/configurations/" + config_name + response = requests.get(host_config_url, headers=headers, verify=False) + return response + +def create_host_configuration(base_url, jwt, host_uuid, config_name, config_value): + headers = {'Content-Type': content_type_header, 'Authorization': jwt} + print("\nCalling Config Hosts API to create the '{}' configuration setting on the host '{}'.".format(config_name, host_uuid)) + + host_config_url = base_url + config_hosts_url + host_uuid + "/configurations" + data = {'data':{'type':'hostConfiguration', 'id':config_name, 'attributes':{'value':config_value}}} + + response = requests.post(host_config_url, headers=headers, json=data, verify=False) + return response + +def update_host_configuration(base_url, jwt, host_uuid, config_name, config_value): + headers = {'Content-Type': content_type_header, 'Authorization': jwt} + print("\nCalling Config Hosts API to update the '{}' configuration setting on the host '{}'.".format(config_name, host_uuid)) + + host_config_url = base_url + config_hosts_url + host_uuid + "/configurations/" + config_name + data = {'data':{'type':'hostConfiguration', 'id':config_name, 'attributes':{'value':config_value}}} + + response = requests.put(host_config_url, headers=headers, json=data, verify=False) + return response + diff --git a/recipes/python/config/hosts_set_exclude_list.py b/recipes/python/config/hosts_set_exclude_list.py new file mode 100644 index 0000000..ce8dde9 --- /dev/null +++ b/recipes/python/config/hosts_set_exclude_list.py @@ -0,0 +1,135 @@ +import sys +import login.login_api as login_api +import config.hosts_api as hosts_api +import config.exclude_list as exclude_list + +nbmaster = "" +username = "" +password = "" +domainName = "" +domainType = "" +hostName = "" + +EXCLUDE_CONFIG_NAME = "Exclude" + +def print_disclaimer(): + print("\n-------------------------------------------------------------------------------------------------") + print("-- This script requires Python3.5 or higher. --") + print("-- The system where this script is run should have Python 3.5 or higher version installed. --") + print("-------------------------------------------------------------------------------------------------") + print("The script requires 'requests' library to make the API calls.") + print("You can install the library using the command: pip install requests") + print("-------------------------------------------------------------------------------------------------") + +def print_usage(): + print("\nCommand-line usage (should be run from the parent directory of the 'config' directory):") + print("\tpython -Wignore -m config.hosts_exclude_list -hostName -nbmaster -username -password [-domainName ] [-domainType ]") + print("Note: hostName is the name of the NetBackup host to set the exclude configuration for. The exclude list is specified in the config/exclude_list file.\n") + print("-------------------------------------------------------------------------------------------------") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print("\nInvalid command!") + print_usage() + exit() + + global nbmaster + global username + global password + global domainName + global domainType + global hostName + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-domainName": + domainName = sys.argv[i + 1] + elif sys.argv[i] == "-domainType": + domainType = sys.argv[i + 1] + elif sys.argv[i] == "-hostName": + hostName = sys.argv[i + 1] + else: + print("\nInvalid command!") + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'\n") + exit() + elif username == "": + print("Please provide the value for 'username'\n") + exit() + elif password == "": + print("Please provide the value for 'password'\n") + exit() + elif domainName == "": + print("Please provide the value for 'domainName'\n") + exit() + elif domainType == "": + print("Please provide the value for 'domainType'\n") + exit() + elif hostName == "": + print("Please provide the value for 'hostName'\n") + exit() + +print_disclaimer() + +print_usage() + +read_command_line_arguments() + +base_url = "https://" + nbmaster + "/netbackup" + +print("\nExecuting the script...") + +jwt = login_api.perform_login(base_url, username, password, domainName, domainType) + +host_uuid = hosts_api.get_host_uuid(base_url, jwt, hostName) + +get_exclude_config_response = hosts_api.get_host_configuration(base_url, jwt, host_uuid, EXCLUDE_CONFIG_NAME) + +if get_exclude_config_response.status_code == 404: + print("No 'Exclude' setting exists. Creating new 'Exclude' configuration.") + response = hosts_api.create_host_configuration(base_url, jwt, host_uuid, EXCLUDE_CONFIG_NAME, exclude_list.EXCLUDE_LIST) + + if response.status_code != 204: + print("\nCreate configuration failed with status code {} and {}".format(response.status_code, response.json())) + raise SystemExit("\n\n") + else: + print("Create configuration successful.") + +elif get_exclude_config_response.status_code == 200: + print("Current 'Exclude' list is:") + excludes = get_exclude_config_response.json()['data']['attributes']['value'] + for exclude in excludes: + print("\t" + exclude) + + print("\nUpdating the 'Exclude' configuration setting.") + response = hosts_api.update_host_configuration(base_url, jwt, host_uuid, EXCLUDE_CONFIG_NAME, exclude_list.EXCLUDE_LIST) + + if response.status_code != 204: + print("\nUpdate configuration failed with status code {} and {}".format(response.status_code, response.json())) + raise SystemExit("\n\n") + else: + print("Update configuration successful.") + +print("\nGetting the new exclude list setting.") +get_exclude_config_response_new = hosts_api.get_host_configuration(base_url, jwt, host_uuid, EXCLUDE_CONFIG_NAME) + +if get_exclude_config_response_new.status_code != 200: + print("\nCould not get the new Exclude setting. Get configuration failed with status code {} and {}" + .format(get_exclude_config_response_new.status_code, get_exclude_config_response_new.json())) + raise SystemExit("\n\n") + +print("The new 'Exclude' list set on the host {} is:".format(hostName)) +excludes_new = get_exclude_config_response_new.json()['data']['attributes']['value'] +for exclude in excludes_new: + print("\t" + exclude) + +print("\nScript completed successfully!\n") + diff --git a/recipes/python/login/login_api.py b/recipes/python/login/login_api.py new file mode 100644 index 0000000..952e1f7 --- /dev/null +++ b/recipes/python/login/login_api.py @@ -0,0 +1,22 @@ +import requests + +content_type = "application/vnd.netbackup+json;version=3.0" + +def perform_login(base_url, username, password, domainName, domainType): + url = base_url + "/login" + req_body = {'userName': username, 'password': password, 'domainName': domainName, 'domainType': domainType} + headers = {'Content-Type': content_type} + + print("\nLogin user '{}'.".format(req_body['userName'])) + + resp = requests.post(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 201: + print("\nLogin API failed with status code {} and {}".format(resp.status_code, resp.json())) + raise SystemExit("\nLogin failed. Please verify that the input parameters are correct and try again.\n") + + print("Login API returned response status code: {}".format(resp.status_code)) + + print("Login successful. Returning the JWT.") + + return resp.json()['token'] diff --git a/recipes/python/policies/README.md b/recipes/python/policies/README.md new file mode 100644 index 0000000..b79b7ff --- /dev/null +++ b/recipes/python/policies/README.md @@ -0,0 +1,26 @@ +### NetBackup API Code Samples for Policy APIs + +This directory contains code samples in Python to invoke NetBackup Policy APIs. + +#### Disclaimer + +These samples are provided only as reference and not meant for production use. + +#### Executing the scripts + +Pre-requisites: +- NetBackup 8.1.2 or higher + + - **NOTE:** The following scripts configure access control using the old RBAC design and will only work on NetBackup + release 8.1.2 or 8.2. + - recipes/perl/policies/api_requests_rbac_policy.py + - recipes/perl/policies/rbac_filtering_in_policy.py + +- Python 3.5 or higher +- Python modules: `requests` + + +Use the following commands to run the scripts. +- Create a test policy, add clients, backup selections and schedules to the policy, and delete the policy: `python -W ignore create_policy_step_by_step.py -nbmaster -username -password [-domainName ] [-domainType ]` +- Create a test policy with default values, and delete the policy: `python -W ignore create_policy_in_one_step.py -nbmaster -username -password [-domainName ] [-domainType ]` +- Create RBAC access rule, set object-level permission on policies for test user, create and read policies as per the RBAC permissions, and delete the test policies: `python -W ignore rbac_filtering_in_policy.py -nbmaster -username -password [-domainName ] [-domainType ]` diff --git a/recipes/python/create_policy_in_one_step.py b/recipes/python/policies/create_policy_in_one_step.py similarity index 100% rename from recipes/python/create_policy_in_one_step.py rename to recipes/python/policies/create_policy_in_one_step.py diff --git a/recipes/python/create_policy_step_by_step.py b/recipes/python/policies/create_policy_step_by_step.py similarity index 100% rename from recipes/python/create_policy_step_by_step.py rename to recipes/python/policies/create_policy_step_by_step.py diff --git a/recipes/python/policies/create_update_delete_policy_sample.py b/recipes/python/policies/create_update_delete_policy_sample.py new file mode 100644 index 0000000..72deaf2 --- /dev/null +++ b/recipes/python/policies/create_update_delete_policy_sample.py @@ -0,0 +1,143 @@ +import sys +import policy_api_request_helper +import json + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainName = "" +domainType = "" +port = 1556 + + +def print_disclaimer(): + print("-------------------------------------------------------------------------------------------------") + print("-- This script requires Python3.5 or higher. --") + print("-- If your current system does not have Python3.5 or higher installed, this will not work. --") + print("-------------------------------------------------------------------------------------------------\n") + print("Executing this library requires some additional python3.5 libraries like \n\t'requests'.\n\n") + print("You will, however, require 'requests' library to make the API calls.\n") + print("You can install the dependent libraries using the following commands: ") + print("pip install requests") + print("-------------------------------------------------------------------------------------------------\n\n\n") + print( + "You can specify the 'nbmaster', 'username', 'password', 'domainName' and 'domainType' as command-line parameters\n") + print_usage() + + +def print_usage(): + print("Example:") + print( + "python -W ignore create_policy_in_one_step.py -nbmaster -username -password [-domainName ] [-domainType ]\n\n\n") + + +def read_command_line_arguments(): + if len(sys.argv) % 2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainName + global domainType + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-domainName": + domainName = sys.argv[i + 1] + elif sys.argv[i] == "-domainType": + domainType = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + exit() + elif domainName == "": + print("Please provide the value for 'domainName'") + exit() + elif domainType == "": + print("Please provide the value for 'domainType'") + exit() + + +print_disclaimer() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = policy_api_request_helper.perform_login(username, password, domainName, domainType, base_url) + +policy_id = "test_Standard_ID_001" +policy_name = "test_standard_sample_name" +policy_type = "Standard" +new_policy_name_for_copy = "test_standard_sample_name_copied" + +policy_api_request_helper.create_netbackup_policy(jwt, base_url, policy_id, policy_name,policy_type) + +policy_api_request_helper.get_netbackup_policy(jwt, base_url, policy_name) + +policy_api_request_helper.get_netbackup_policies(jwt, base_url) + +policy_api_request_helper.copy_netbackup_policy(jwt, base_url, policy_name, new_policy_name_for_copy) + +policy_api_request_helper.get_netbackup_policy(jwt, base_url, new_policy_name_for_copy) + +policy_api_request_helper.delete_netbackup_policy(jwt, base_url, policy_name) + +policy_api_request_helper.delete_netbackup_policy(jwt, base_url, new_policy_name_for_copy) + +policy_api_request_helper.get_netbackup_policies(jwt, base_url) + +policy_id = "test_Standard_ID_002" +policy_name = "test_windows_sample_name" +policy_type = "Windows" +new_policy_name_for_copy = "test_windows_sample_name_copied" +client_name = "testClient001" +schedule_name = "testSechedule001" +test_backup_selection = "testBackupSelection" + +policy_api_request_helper.create_netbackup_policy(jwt, base_url, policy_id, policy_name,policy_type) + +policy_api_request_helper.get_netbackup_policy(jwt, base_url, policy_name) + +policy_api_request_helper.get_netbackup_policies(jwt, base_url) + +policy_api_request_helper.put_netbackup_client(jwt,policy_name,client_name,policy_type) + +policy_api_request_helper.get_netbackup_unique_policy_clients(jwt,base_url) + +policy_api_request_helper.copy_netbackup_policy(jwt, base_url, policy_name, new_policy_name_for_copy) + +policy_api_request_helper.get_netbackup_policy(jwt, base_url, new_policy_name_for_copy) + +policy_api_request_helper.get_netbackup_policies(jwt, base_url) + +policy_api_request_helper.put_netbackup_backupselections(jwt,base_url,policy_name,test_backup_selection) + +policy_api_request_helper.delete_netbackup_backupselections(jwt,base_url, test_backup_selection) + +policy_api_request_helper.delete_netbackup_backupselections(jwt,base_url,policy_name) + +policy_api_request_helper.delete_netbackup_client(jwt,policy_name,client_name) + +policy_api_request_helper.delete_netbackup_client(jwt,new_policy_name_for_copy,client_name) + +policy_api_request_helper.delete_netbackup_policy(jwt, base_url, policy_name) + +policy_api_request_helper.delete_netbackup_policy(jwt, base_url, new_policy_name_for_copy) \ No newline at end of file diff --git a/recipes/python/policies/policy_api_request_helper.py b/recipes/python/policies/policy_api_request_helper.py new file mode 100644 index 0000000..1db32c3 --- /dev/null +++ b/recipes/python/policies/policy_api_request_helper.py @@ -0,0 +1,253 @@ +import requests +import json + +content_type = "application/vnd.netbackup+json; version=4.0" +etag = "" + +def perform_login(username, password, domainName, domainType, base_url): + url = base_url + "/login" + req_body = {"userName": username, "password": password, "domainName": domainName, "domainType": domainType} + headers = {'Content-Type': content_type} + + print("Making POST Request to login for user '{}'\n".format(req_body['userName'])) + + resp = requests.post(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 201: + print('Login API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + + print("\nThe response code of the Login API: {}\n".format(resp.status_code)) + + return resp.json()['token'] + +def create_netbackup_policy(jwt, base_url, policy_id, policy_name, policy_type): + url = base_url + "/config/policies/" + req_body = { + "data": { + "type": "policy", + "id": policy_id, + "attributes": { + "policy": { + "policyName": policy_name, + "policyType": policy_type, + "policyAttributes": {}, + "clients": [], + "schedules": [], + "backupSelections": { + "selections": [] + } + } + } + } + } + headers = {'Content-Type': content_type, 'Authorization': jwt} + + print("\nMaking POST Request to create Policy with defaults \n") + + resp = requests.post(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 204: + print( + 'Create Policy API with defaults failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + + print("\n Policy with PolicyID {}, Policy Name {} and Policy Type {} is created with status code : {}\n".format(policy_id, policy_name, policy_type, resp.status_code)) + + +def get_netbackup_policies(jwt, base_url): + url = base_url + "/config/policies" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + print("\nMaking GET Request to list policies ") + + resp = requests.get(url, headers=headers, verify=False) + + if resp.status_code != 200: + print('List Policies API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + + print("\nList policy succeeded with status code: {}\n".format(resp.status_code)) + print("\n Json Response body for List policies : \n{}\n".format(json.loads(resp.content))) + + +def get_netbackup_policy(jwt, base_url, policy_name): + url = base_url + "/config/policies/" + policy_name + global etag + headers = {'Content-Type': content_type, 'Authorization': jwt} + + print("\nperforming GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, verify=False) + + if resp.status_code != 200: + print('GET Policy API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + + print("\nGet policy details on {} succeeded with status code: {}\n".format(policy_name, resp.status_code)) + print("\n The E-tag for the get policy : {}\n".format(resp.headers['ETag'])) + etag = resp.headers['ETag'] + print("\n Json Response body for get policy : \n{}\n".format(json.loads(resp.content))) + +def copy_netbackup_policy(jwt, base_url, existing_policy_name, new_policy_name): + url = base_url + "/config/policies/" + existing_policy_name + "/copy" + req_body = { + "data": { + "type": "copyPolicyRequest", + "id": new_policy_name, + "attributes": { + "copyPolicyRequest": { + "id": new_policy_name + } + } + } + } + headers = {'Content-Type': content_type, 'Authorization': jwt} + + print("\nMaking POST Request to copy Policy \n") + + resp = requests.post(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 204: + print( + 'Copy Policy API with defaults failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + + print("\n Policy with Policy name {} has been to a new policy named {} with status code : {}\n".format(existing_policy_name, new_policy_name, resp.status_code)) + + + +def delete_netbackup_policy(jwt, base_url, policy_name): + url = base_url + "/config/policies/" + policy_name + headers = {'Content-Type': content_type, 'Authorization': jwt, 'If-Match': etag} + + print("\n Making policy DELETE Request on {}".format(policy_name)) + + resp = requests.delete(url, headers=headers, verify=False) + + if resp.status_code != 204: + print('DELETE Policy API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + + print("\nThe policy is deleted with status code: {}\n".format(resp.status_code)) + + +def put_netbackup_policy(jwt, base_url, policy_id, policy_name, policy_type): + url = base_url + "/config/policies/" + policy_name + global etag + req_body = { + "data": { + "type": "policy", + "id": policy_id, + "attributes": { + "policy": { + "policyName": policy_name, + "policyType": policy_type, + "policyAttributes": { + "keyword": "test" + }, + "clients": [], + "schedules": [], + "backupSelections": { + "selections": [] + } + } + } + } + } + headers = {'Content-Type': content_type, 'Authorization': jwt, 'If-Match': etag} + + print("\n Making Update Request on {} by changing few attributes of the policy".format(policy_name)) + + resp = requests.put(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 204: + print('PUT Policy API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + etag = resp.headers['ETag'] + print("\n{} Updated with status code : {}\n".format(policy_name, resp.status_code)) + + +def put_netbackup_client(jwt, base_url, policy_name, client_name, policy_type): + url = base_url + "/config/policies/" + policy_name + "/clients/" + client_name + global etag + req_body = { + "data": { + "type": "client", + "attributes": { + "hardware": policy_type, + "hostName": client_name, + "OS": "VMware" + } + } + } + headers = {'Content-Type': content_type, 'Authorization': jwt, 'If-Match': etag} + + print("\n Making PUT Request to add client to {}".format(policy_name)) + + resp = requests.put(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 201: + print('PUT Client API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + etag = resp.headers['ETag'] + print("\n{} is added to {} with status code : {}\n".format(client_name, policy_name, resp.status_code)) + +def get_netbackup_unique_policy_clients(jwt, base_url): + url = base_url + "/config/unique-policy-clients" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + print("\nMaking GET Request to list unique clients associated with policies ") + + resp = requests.get(url, headers=headers, verify=False) + + if resp.status_code != 200: + print('Unique policy clients API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + + print("\nUnique policy clients succeeded with status code: {}\n".format(resp.status_code)) + print("\n Json Response body for Unique policy clients : \n{}\n".format(json.loads(resp.content))) + +def delete_netbackup_client(jwt, base_url, policy_name, client_name): + url = base_url + "/config/policies/" + policy_name + "/clients/" + client_name + global etag + headers = {'Content-Type': content_type, 'Authorization': jwt, 'If-Match': etag} + + print("\nMaking DELETE Request to remove clients from the policy\n") + + resp = requests.delete(url, headers=headers, verify=False) + + if resp.status_code != 204: + print('DELETE Client API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + etag = resp.headers['ETag'] + print("\nClient {} is deleted from {} with status code: {}\n".format(client_name, policy_name, + resp.status_code)) + +def put_netbackup_backupselections(jwt, base_url, policy_name, testBackupSelectionName): + url = base_url + "/config/policies/" + policy_name + "/backupselections" + global etag + req_body = { + "data": { + "type": "backupSelection", + "attributes": { + "selections": [ + "vmware:/?filter=Displayname Equal \"" + testBackupSelectionName + "\"" + ] + } + } + } + headers = {'Content-Type': content_type, 'Authorization': jwt, 'If-Match': etag} + + print("\nMaking PUT Request to add BackupSelections to {}\n".format(policy_name)) + + resp = requests.put(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 204: + print('PUT Backupselections API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + etag = resp.headers['ETag'] + print("\n Backupselections added to {} with status code: {}\n".format(policy_name, resp.status_code)) + +def delete_netbackup_backupselections(jwt, base_url, policy_name): + url = base_url + "/config/policies/" + policy_name + "/backupselections" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + print("Making DELETE Request to remove Backupselections from the policy\n") + + resp = requests.delete(url, headers=headers, verify=False) + + if resp.status_code != 204: + print('DELETE Backupselections API failed with status code {} and {}\n'.format(resp.status_code, resp.json())) + + print("\n BackupSelections is deleted for the {} with status code : {}\n".format(policy_name, + resp.status_code)) \ No newline at end of file diff --git a/recipes/python/policy_api_requests.py b/recipes/python/policies/policy_api_requests.py similarity index 100% rename from recipes/python/policy_api_requests.py rename to recipes/python/policies/policy_api_requests.py diff --git a/recipes/python/rbac_filtering_in_policy.py b/recipes/python/policies/rbac_filtering_in_policy.py similarity index 100% rename from recipes/python/rbac_filtering_in_policy.py rename to recipes/python/policies/rbac_filtering_in_policy.py diff --git a/recipes/python/rbac_policy_api_requests.py b/recipes/python/policies/rbac_policy_api_requests.py similarity index 100% rename from recipes/python/rbac_policy_api_requests.py rename to recipes/python/policies/rbac_policy_api_requests.py diff --git a/recipes/python/storage/README.md b/recipes/python/storage/README.md new file mode 100644 index 0000000..a709199 --- /dev/null +++ b/recipes/python/storage/README.md @@ -0,0 +1,18 @@ +### NetBackup API Code Samples for Python + +This directory contains code samples to invoke NetBackup REST APIs using Python. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Executing the recipes in Python + +Pre-requisites: +- NetBackup 8.2 or higher +- python 3.5 or higher +- python modules: `requests` + + +Use the following commands to run the python samples. +- `python -W ignore configure_storage_unit_end_to_end.py -nbmaster -username -password -sts_payload -dp_payload -stu_payload [-domainname ] [-domaintype ]` diff --git a/recipes/python/storage/configure_storage_unit_end_to_end.py b/recipes/python/storage/configure_storage_unit_end_to_end.py new file mode 100644 index 0000000..a74e57b --- /dev/null +++ b/recipes/python/storage/configure_storage_unit_end_to_end.py @@ -0,0 +1,94 @@ +import sys +import storage +import json +import texttable as tt + +# This script consists of the helper functions to excute NetBackup APIs to create storage unit. +# 1) Login to Netbackup +# 2) Create storage server +# 3) Create disk Pool +# 4) Create storage unit + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore configure_storage_unit_end_to_end.py -nbmaster -username -password -sts_payload -dp_payload -stu_payload [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global sts_payload + global dp_payload + global stu_payload + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-sts_payload": + sts_payload = sys.argv[i + 1] + elif sys.argv[i] == "-dp_payload": + dp_payload = sys.argv[i + 1] + elif sys.argv[i] == "-stu_payload": + stu_payload = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + exit() + elif sts_payload == "": + print("Please provide the value for 'sts_payload'") + exit() + elif dp_payload == "": + print("Please provide the value for 'dp_payload'") + exit() + elif stu_payload == "": + print("Please provide the value for 'stu_payload'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +response_sts = storage.create_storage_server(jwt, base_url, sts_payload) +print(response_sts) + +response_dp = storage.create_disk_pool(jwt, base_url, dp_payload) +print(response_dp) + +response_stu = storage.create_storage_unit(jwt, base_url, stu_payload) +print(response_stu) diff --git a/recipes/python/storage/storage.py b/recipes/python/storage/storage.py new file mode 100644 index 0000000..9e34c53 --- /dev/null +++ b/recipes/python/storage/storage.py @@ -0,0 +1,284 @@ +import requests + +content_type = "application/vnd.netbackup+json; version=3.0" + + +def perform_login(username, password, base_url, domain_name, domain_type): + url = base_url + "/login" + + if domain_name != "" and domain_type != "": + req_body = {"userName": username, "password": password, "domainName": domain_name, "domainType": domain_type} + else: + req_body = {"userName": username, "password": password} + + headers = {'Content-Type': content_type} + + print("performing POST on {} for user '{}'\n".format(url, req_body['userName'])) + + resp = requests.post(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Login API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json()['token'] + +def get_storage_units(jwt, base_url): + url = base_url + "/storage/storage-units" + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET STU API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def get_storage_servers(jwt, base_url): + url = base_url + "/storage/storage-servers" + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET STS API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def create_storage_server(jwt, base_url, file_name): + url = base_url + "/storage/storage-servers" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing POST on {}\n".format(url), req_body) + + resp = requests.post(url, headers=headers, data=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Create STS API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +def patch_storage_server(jwt, base_url, file_name, stsid): + url = base_url + "/storage/storage-servers/" + stsid + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing PATCH on {}\n".format(url)) + + resp = requests.patch(url, headers=headers, data=req_body, verify=False) + + + if resp.status_code != 200: + raise Exception('Update STS API failed with status code {} and {}'.format(resp.status_code, resp.json())) + print("\nThe STS is Upadated with status code: {}\n".format(resp.status_code)) + return resp.json() + +def patch_storage_unit(jwt, base_url, file_name, stu_name): + url = base_url + "/storage/storage-units/" +stu_name + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing PATCH on {}\n".format(url)) + + resp = requests.patch(url, headers=headers, data=req_body, verify=False) + + + if resp.status_code != 200: + raise Exception('Update STU API failed with status code {} and {}'.format(resp.status_code, resp.json())) + print("\nThe STU is Upadated with status code: {}\n".format(resp.status_code)) + return resp.json() + +def patch_disk_pool(jwt, base_url, file_name, dpid): + url = base_url + "/storage/disk-pools/" +dpid + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing PATCH on {}\n".format(url)) + + resp = requests.patch(url, headers=headers, data=req_body, verify=False) + + if resp.status_code != 200: + raise Exception('Update DP API failed with status code {} and {}'.format(resp.status_code, resp.json())) + print("\nThe DP is Upadated with status code: {}\n".format(resp.status_code)) + return resp.json() + + +def create_disk_pool(jwt, base_url, file_name): + url = base_url + "/storage/disk-pools" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing POST on {}\n".format(url), req_body) + + resp = requests.post(url, headers=headers, data=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Create DP API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def create_storage_unit(jwt, base_url, file_name): + url = base_url + "/storage/storage-units" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing POST on {}\n".format(url), req_body) + + resp = requests.post(url, headers=headers, data=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Create STU API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def get_disk_pools(jwt, base_url): + url = base_url + "/storage/disk-pools" + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET DP API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +def get_disk_pools_by_id(jwt, base_url, dpid): + url = base_url + "/storage/disk-pools/" +dpid + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET DP with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +def get_storage_server_by_id(jwt, base_url, stsid): + url = base_url + "/storage/storage-servers/" +stsid + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET STS with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +def get_storage_unit_by_id(jwt, base_url, stu_name): + url = base_url + "/storage/storage-units/" +stu_name + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET STU with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def delete_storage_server(jwt, base_url, stsid): + url = base_url + "/storage/storage-servers/" +stsid + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing DELETE on {}\n".format(url)) + + resp = requests.delete(url, headers=headers, verify=False) + + if resp.status_code != 204: + raise Exception('DELETE STS with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + print("\nThe STS is deleted with status code: {}\n".format(resp.status_code)) + +def delete_storage_unit(jwt, base_url, stu_name): + url = base_url + "/storage/storage-units/" +stu_name + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing DELETE on {}\n".format(url)) + + resp = requests.delete(url, headers=headers, verify=False) + + if resp.status_code != 204: + raise Exception('DELETE STU with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + print("\nThe STU is deleted with status code: {}\n".format(resp.status_code)) + +def delete_disk_pools(jwt, base_url, dpid): + url = base_url + "/storage/disk-pools/" +dpid + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing DELETE on {}\n".format(url)) + + resp = requests.delete(url, headers=headers, verify=False) + if resp.status_code != 204: + raise Exception('DELETE DP with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + print("\nThe DP is deleted with status code: {}\n".format(resp.status_code)) \ No newline at end of file diff --git a/recipes/python/vmware-agentless/README.md b/recipes/python/vmware-agentless/README.md new file mode 100644 index 0000000..e1dc339 --- /dev/null +++ b/recipes/python/vmware-agentless/README.md @@ -0,0 +1,51 @@ +### NetBackup API Code Samples for VMware Agentless Restore APIs + +This directory contains code samples in Python to invoke NetBackup Agentless Restore APIs. + +#### Disclaimer + +These samples are provided only as reference and not meant for production use. + +#### Executing the script + +Pre-requisites: +- NetBackup 8.2 or higher +- Python 3.7 or higher +- Python modules: `requests`, `texttable` + + + +Without arguments the script will prompt for the necessary inputs. +- `python vmware_agentless_restore.py` + +All parameters can also be passed as command line arguments. +- `python vmware_agentless_restore.py --help` +``` +usage: vmware_agentless_restore.py [-h] [--master MASTER] + [--username USERNAME] [--password PASSWORD] + [--port PORT] [--vm_name VM_NAME] + [--vm_username VM_USERNAME] + [--vm_password VM_PASSWORD] [--file FILE] + [--destination DESTINATION] + [--no_check_certificate] + +Sample script demonstrating NetBackup agentless restore for VMware + +optional arguments: + -h, --help show this help message and exit + --master MASTER NetBackup master server + --username USERNAME NetBackup user name + --password PASSWORD NetBackup password + --port PORT NetBackup port (default is 1556) + --vm_name VM_NAME VM name + --vm_username VM_USERNAME + VM user name + --vm_password VM_PASSWORD + VM password + --file FILE File to be restored + --destination DESTINATION + Destination path of file + --no_check_certificate + Disable certificate verification +``` + diff --git a/recipes/python/vmware-agentless/vmware_agentless_restore.py b/recipes/python/vmware-agentless/vmware_agentless_restore.py new file mode 100644 index 0000000..7bfc14b --- /dev/null +++ b/recipes/python/vmware-agentless/vmware_agentless_restore.py @@ -0,0 +1,130 @@ +import argparse +import os +import getpass +import requests +import texttable as tt +from requests.packages.urllib3.exceptions import InsecureRequestWarning + +parser = argparse.ArgumentParser(description="Sample script demonstrating NetBackup agentless restore for VMware") +parser.add_argument("--master", type=str, help="NetBackup master server") +parser.add_argument("--username", type=str, help="NetBackup user name") +parser.add_argument("--password", type=str, help="NetBackup password") +parser.add_argument("--port", type=int, help="NetBackup port (default is 1556)", default=1556) +parser.add_argument("--vm_name", type=str, help="VM name") +parser.add_argument("--vm_username", type=str, help="VM user name") +parser.add_argument("--vm_password", type=str, help="VM password") +parser.add_argument("--file", type=str, help="File to be restored") +parser.add_argument("--destination", type=str, help="Destination path of file") +parser.add_argument("--no_check_certificate", action="store_true", help="Disable certificate verification", default=False) + +args = parser.parse_args() + +if not args.master: + args.master = input("NetBackup master server: ") +if not args.username: + args.username = input("NetBackup user name: ") +if not args.password: + args.password = getpass.getpass("NetBackup password: ") +if not args.vm_name: + args.vm_name = input("VM name: ") +if not args.vm_username: + args.vm_username = input("VM username: ") +if not args.vm_password: + args.vm_password = getpass.getpass("VM password: ") +if not args.file: + args.file = input("File to be restored: ") +if not args.destination: + args.destination = input("File destination: ") +if args.no_check_certificate: + requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + +base_url = "https://" + args.master + ":" + str(args.port) + "/netbackup" +content_type = "application/vnd.netbackup+json;version=3.0" + +url = base_url + "/login" +headers = {"Content-Type": content_type} +resp = requests.post( + url, + headers=headers, + json={"userName": args.username, "password": args.password}, + verify=not args.no_check_certificate, +) +if resp.status_code != 201: + print("NetBackup login failed") + exit(1) +jwt = resp.json()["token"] + +headers = {"Content-Type": content_type, "Authorization": jwt} + +url = base_url + "/assets" +params = {"filter": "displayName eq '" + args.vm_name + "'"} +resp = requests.get(url, headers=headers, params=params, verify=not args.no_check_certificate) +vm_found = False +vm_attributes = None +for asset in resp.json()["data"]: + if asset["attributes"]["displayName"] == args.vm_name: + vm_attributes = asset["attributes"]["extendedAttributes"] + vm_found = True + break +if not vm_found: + print("VM not found in NetBackup asset database") + exit(1) + +url = base_url + "/recovery/workloads/vmware/scenarios/guestfs-agentless/pre-recovery-check" +payload = { + "data": { + "type": "vmAgentlessFilePreRecoveryCheckRequest", + "attributes": { + "recoveryOptions": { + "recoveryHost": args.master, + "vCenter": vm_attributes["vCenter"], + "esxiServer": vm_attributes["hostName"], + "instanceUuid": vm_attributes["instanceUuid"], + "datastore": vm_attributes["datastore"][0], + "vmUsername": args.vm_username, + "vmPassword": args.vm_password, + } + }, + } +} +resp = requests.post(url, headers=headers, json=payload, verify=not args.no_check_certificate) +pre_check_failed = False +tab = tt.Texttable() +headings = ["Pre-recovery check", "Result", "Description"] +tab.header(headings) +for data_item in resp.json()["data"]: + tuple_value = ( + data_item["attributes"]["name"], + data_item["attributes"]["result"], + data_item["attributes"].get("description", ""), + ) + tab.add_row(tuple_value) + if data_item["attributes"]["result"] == "fail": + pre_check_failed = True +print(tab.draw()) +if pre_check_failed: + exit(1) + +url = base_url + "/recovery/workloads/vmware/scenarios/guestfs-agentless/recover" +payload = { + "data": { + "type": "vmAgentlessFileRecoveryRequest", + "attributes": { + "recoveryPoint": {"client": vm_attributes["instanceUuid"]}, + "recoveryObject": { + "vmFiles": [{"source": args.file, "destination": args.destination}], + "vmRecoveryDestination": { + "instanceUuid": vm_attributes["instanceUuid"], + "vmUsername": args.vm_username, + "vmPassword": args.vm_password, + }, + }, + }, + } +} +resp = requests.post(url, headers=headers, json=payload, verify=not args.no_check_certificate) +if resp.status_code != 201: + print("Failed to start restore") + print(resp.json().get("errorMessage")) + exit(1) +print(resp.json()["data"]["attributes"]["msg"]) diff --git a/snippets/ansible/README.md b/snippets/ansible/README.md new file mode 100644 index 0000000..dab0346 --- /dev/null +++ b/snippets/ansible/README.md @@ -0,0 +1,25 @@ +### NetBackup API Code Samples for Ansible + +This directory contains code samples to invoke NetBackup REST APIs using ansible. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.1.1 or higher +- ansible 2.x + + +#### Executing the snippets in ansible + +These are tasks meant to be part of a larger playbook. I use them with the following syntax + +tasks: +-name: name of tasks + include_task: tasklocation/taskname + + +Vars for ansible are defined in a inventory file for use in plays +vars created during plays are used in future ones like login.yml. diff --git a/snippets/ansible/login.yml b/snippets/ansible/login.yml new file mode 100644 index 0000000..8d948de --- /dev/null +++ b/snippets/ansible/login.yml @@ -0,0 +1,22 @@ +--- + - name: login + uri: + url: "{{baseurl}}login" + method: POST + body_format: json + status_code: 201 + headers: + content-type: application/vnd.netbackup+json;version=3.0 + body: + userName: "{{username}}" + password: "{{password}}" + validate_certs: no + return_content: yes + register: login + + - name: set facts + set_fact: + login_token: "{{login.json.token}}" + - name: debug token + debug: + msg: "{{login_token}}" diff --git a/snippets/ansible/msdp_create.yml b/snippets/ansible/msdp_create.yml new file mode 100644 index 0000000..88d2038 --- /dev/null +++ b/snippets/ansible/msdp_create.yml @@ -0,0 +1,93 @@ +--- + + - name: Create storage server + uri: + url: "{{baseurl}}storage/storage-servers" + method: POST + body_format: json + status_code: 201, 409 + headers: + authorization: "{{login.json.token}}" + content-type: application/vnd.netbackup+json;version=3.0 + body: + data: + type: storageServer + attributes: + name: "{{mediaserver}}.{{domain}}" + storageCategory: MSDP + mediaServerDetails: + name: "{{mediaserver}}.{{domain}}" + encryptionEnabled: false + msdpAttributes: + storagePath: /mnt/msdp/vol0 + credentials: + userName: msdp + password: msdp + validate_certs: no + return_content: yes + register: stgsvr_create + - name: debug stgsvr_create + debug: + msg: "{{stgsvr_create}}" + + - name: Create MSDP Disk Pool + uri: + url: "{{baseurl}}storage/disk-pools" + method: POST + body_format: json + status_code: 201, 409 + headers: + authorization: "{{login.json.token}}" + content-type: application/vnd.netbackup+json;version=3.0 + body: + data: + type: diskPool + attributes: + name: "{{mediaserver}}"_dpm + diskVolumes: + - name: PureDiskVolume + maximumIoStreams: + limitIoStreams: true + streamsPerVolume: 75 + relationships: + storageServers: + data: + - type: storageServer + id: "PureDisk:{{mediaserver}}.{{domain}}" + validate_certs: no + return_content: yes + register: dp_create + - name: debug dp_Create + debug: + msg: "{{dp_create}}" + + - name: Create MSDP Storage Unit + uri: + url: "{{baseurl}}storage/storage-units" + method: POST + body_format: json + status_code: 201 + headers: + authorization: "{{login.json.token}}" + content-type: application/vnd.netbackup+json;version=3.0 + body: + data: + type: storageUnit + attributes: + name: "{{mediaserver}}"_dpm_su + useAnyAvailableMediaServer: true + maxFragmentSizeMegabytes: 51200 + maxConcurrentJobs: 100 + onDemandOnly: true + relationships: + diskPool: + data: + type: diskPool + id: "PureDisk:"{{mediaserver}}"_dpm" + validate_certs: no + return_content: yes + register: stu_create + - name: debug stu_Create + debug: + msg: "{{stu_create}}" + diff --git a/snippets/ansible/slo_post_example b/snippets/ansible/slo_post_example new file mode 100644 index 0000000..e319829 --- /dev/null +++ b/snippets/ansible/slo_post_example @@ -0,0 +1,147 @@ +--- + ### Requirements + # inputs from parent - {{login_token}}, + # inputs from inventory - {{baseurl}}, {{master}}, {{vcenter}} + # outputs {{slo_create}} + - name: SLO Create + uri: + url: "{{baseurl}}servicecatalog/slos" + method: POST + body_format: json + status_code: 201 + headers: + authorization: "{{login_token}}" + content-type: "{{contenttype}}" + body: + data: + type: slov3 + attributes: + name: "ams03_{{item.seg}}v_{{item.type}}_fr_{{item.time}}_{{item.ret}}_ansible_test" + description: "ansible testing protection plans" + policyNamePrefix: "dc01_{{item.seg}}v_{{item.type}}_fr_{{item.time}}_{{item.ret}}_ansible_test" + workloadType: VMWARE + schedules: + - scheduleType: FULL + frequencySeconds: 604800 + retention: + value: 30 + unit: DAYS + backupStorageUnit: dc01nbumed01_dpm_su + backupWindows: + - dayOfWeek: 6 + durationSeconds: 28800 + startSeconds: 64800 + - scheduleType: DIFFERENTIAL_INCREMENTAL + frequencySeconds: 86400 + retention: + value: 30 + unit: DAYS + backupStorageUnit: dc01nbumed01_dpm_su + backupWindows: + - dayOfWeek: 1 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 2 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 3 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 4 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 5 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 7 + durationSeconds: 28800 + startSeconds: 64800 + policyDefinition: + policy: + policyName: "dc1_{{item.seg}}v_{{item.type}}_fr_{{item.time}}_{{item.ret}}_ansible_test" + policyType: VMware + policyAttributes: + active: false + jobLimit: 2147483647 + snapshotMethodArgs: "skipnodisk=0,post_events=1,multi_org=0,Virtual_machine_backup=2,continue_discovery=1,nameuse=4,exclude_swap=1,tags_unset=0,ignore_irvm=1,rLim=10,snapact=2,enable_quiesce_failover=1,file_system_optimization=1,drive_selection=0,disable_quiesce=0,enable_vCloud=0,trantype=nbdssl,rHz=10,rTO=0" + useAccelerator: true + autoManagedType: 2 + backupHost: MEDIA_SERVER + blockIncremental: true + dataClassification: + disableClientSideDeduplication: false + discoveryLifetime: 28800 + mediaOwner: "*ANY*" + priority: 0 + storage: + storageIsSLP: false + useReplicationDirector: false + volumePool: NetBackup + schedules: + - backupType: Full Backup + backupCopies: + copies: + - retentionPeriod: + value: 1 + unit: DAYS + storage: SLO_UUID_bd72e69e-c3d4-4446-8273-4646b1f5d614_Backup_Only_29d7ad56-1ab7-4876-a00f-4868433ea149 + priority: -1 + frequencySeconds: 604800 + mediaMultiplexing: 1 + retriesAllowedAfterRunDay: false + scheduleName: Full + scheduleType: Frequency + snapshotOnly: false + storageIsSLP: true + startWindow: + - dayOfWeek: 6 + durationSeconds: 28000 + startSeconds: 64800 + - backupType: "Differential Incremental Backup" + backupCopies: + copies: + - retentionPeriod: + value: 1 + unit: DAYS + storage: SLO_UUID_bd72e69e-c3d4-4446-8273-4646b1f5d614_Backup_Only_29d7ad56-1ab7-4876-a00f-4868433ea149 + priority: -1 + frequencySeconds: 86400 + mediaMultiplexing: 1 + retriesAllowedAfterRunDay: false + scheduleName: DIFF_INC + scheduleType: Frequency + snapshotOnly: false + storageIsSLP: true + startWindow: + - dayOfWeek: 1 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 2 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 3 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 4 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 5 + durationSeconds: 28800 + startSeconds: 64800 + - dayOfWeek: 7 + durationSeconds: 28800 + startSeconds: 64800 + validate_certs: no + return_content: yes + + with_items: + - { seg: 'e', time: '1800', type: 'wi', ret: '30' } + - { seg: 'i', time: '1800', type: 'wi', ret: '30' } + - { seg: 's', time: '1800', type: 'wi', ret: '30' } + +# validate_certs: no +# return_content: yes + register: slo_create + - name: debug vmware_resource + debug: + msg: "{{slo_create}}" diff --git a/snippets/ansible/vmware_resourcelimits.yml b/snippets/ansible/vmware_resourcelimits.yml new file mode 100644 index 0000000..c6f4175 --- /dev/null +++ b/snippets/ansible/vmware_resourcelimits.yml @@ -0,0 +1,30 @@ +--- + - name: vmware resource limits + uri: + url: "{{baseurl}}config/resource-limits" + method: POST + body_format: json + status_code: 204 + headers: + authorization: "{{login.json.token}}" + content-type: application/vnd.netbackup+json;version=3.0 + body: + data: + - type: resource-limits + id: vmware + attributes: + resources: + - resourceType: vCenter + resourceLimit: 50 + - resourceType: ESXserver + resourceLimit: 2 + - resourceType: Datastore + resourceLimit: 2 + + validate_certs: no + return_content: yes + register: vmware_resource + - name: debug vmware_resource + debug: + msg: "{{vmware_resource}}" + diff --git a/snippets/curl/README.md b/snippets/curl/README.md index 2680397..2e5182c 100644 --- a/snippets/curl/README.md +++ b/snippets/curl/README.md @@ -9,6 +9,7 @@ These scripts are only meant to be used as a reference. If you intend to use the #### Pre-requisites: - NetBackup 8.1.1 or higher +- NetBackup 8.2 or higher for using API keys related APIs and samples - curl 7.51.0 or higher - jq command-line parser (https://github.com/stedolan/jq/releases) @@ -17,3 +18,17 @@ These scripts are only meant to be used as a reference. If you intend to use the Use the following commands to run the curl samples. - `./get_nb_jobs.sh -nbmaster -username -password -domainname -domaintype ` - `./get_nb_images.sh -nbmaster -username -password -domainname -domaintype ` + +#### Scripts for NetBackup 8.2 or higher + +- Use the following command to create an API key for yourself on your NetBackup Master server: + - `./apikey_create.sh -nbmaster -login_username -login_password -login_domainname -login_domaintype -expiryindays -description ` + +- Use the following command to create an API key for other user on your NetBackup Master server: + - `./apikey_create.sh -nbmaster -login_username -login_password -login_domainname -login_domaintype -apikey_username [-apikey_domainname ] -apikey_domaintype -expiryindays -description ` + +- Use the following command to delete an API key on your NetBackup Master server with apikey tag provided: + - `./apikey_delete.sh -nbmaster -login_username -login_password -login_domainname -login_domaintype -apikey_tag ` + +Use the following command to use API key instead of JWT to trigger a NetBackup REST API on your NetBackup Master server: + - `./apikey_usage.sh -nbmaster -apikey ` \ No newline at end of file diff --git a/snippets/curl/apikey_create.sh b/snippets/curl/apikey_create.sh new file mode 100755 index 0000000..f2823d7 --- /dev/null +++ b/snippets/curl/apikey_create.sh @@ -0,0 +1,152 @@ +#!/bin/sh + +#####################n##################################################### + +# This script demonstrates how to create API key for a user (self/others). To +# create API key for other user, a user needs to have proper permissions. + +# This script requires jq command-line JSON parser +# if your system does not have jq installed, this will not work. +# jq can be downloaded from here: https://github.com/stedolan/jq/releases + +########################################################################### + +port=1556 +master_server="" +login_username="" +login_password="" +login_domainname="" +login_domaintype="" +apikey_username="" +apikey_domainname="" +apikey_domaintype="" +expiryindays="" +description="" +apikey_other_user=0 + +showHelp() +{ + echo "" + echo "Invalid command parameters" + echo "Usage:" + echo "./apikey_create.sh -nbmaster -login_username -login_password -login_domainname -login_domaintype [-apikey_username [-apikey_domainname ] -apikey_domaintype ] -expiryindays -description " + echo "-nbmaster : Name of the NetBackup master server" + echo "-login_username : User name of the user performing action" + echo "-login_password : Password of the user performing action" + echo "-login_domainname : Domain name of the user performing action" + echo "-login_domaintype : Domain type of the user performing action" + echo "-apikey_username : (Optional) User name of the user for whom API key needs to be generated. Optional in case API key is to be generated for self" + echo "-apikey_domainname : Domain name of the user for whom API key needs to be generated. Optional in case API key is to be generated for self. Do not specify this parameter if -apikey_domaintype parameter is 'unixpwd'" + echo "-apikey_domaintype : Domain type of the user for whom API key needs to be generated. Optional in case API key is to be generated for self" + echo "-expiryindays : Number of days from today after which API key should expire" + echo "-description : A textual description to be associated with API key" + echo "" + exit 1 +} + +parseArguments() +{ + if [ $# -ne 14 ] && [ $# -ne 18 ] && [ $# -ne 20 ]; then + showHelp + fi + + while [ "$1" != "" ]; do + case $1 in + -nbmaster) + master_server=$2 + ;; + -login_username) + login_username=$2 + ;; + -login_password) + login_password=$2 + ;; + -login_domainname) + login_domainname=$2 + ;; + -login_domaintype) + login_domaintype=$2 + ;; + -apikey_username) + apikey_username=$2 + apikey_other_user=1 + ;; + -apikey_domainname) + apikey_domainname=$2 + apikey_other_user=1 + ;; + -apikey_domaintype) + apikey_domaintype=$2 + apikey_other_user=1 + ;; + -expiryindays) + expiryindays=$2 + ;; + -description) + description=$2 + ;; + *) + showHelp + ;; + esac + shift 2 + done + + if [ -z "$master_server" ] || [ -z "$login_username" ] || [ -z "$login_password" ] || [ -z "$login_domainname" ] || [ -z "$login_domaintype" ] || [ -z "$expiryindays" ] || [ -z "$description" ]; then + showHelp + fi + + if [ $apikey_other_user -eq 1 ]; then + if [ -z "$apikey_username" ] || [ -z "$apikey_domaintype" ]; then + showHelp + fi + fi + + if [ "${login_domaintype^^}" = "WINDOWS" ] || [ "${login_domaintype^^}" = "NT" ]; then + login_domaintype="nt" + fi + + if [ "${apikey_domaintype^^}" = "WINDOWS" ] || [ "${apikey_domaintype^^}" = "NT" ]; then + apikey_domaintype="nt" + fi +} + +###############main############ + +parseArguments "$@" + +basepath="https://$master_server:$port/netbackup" +content_header='content-type:application/json' + +##############login############# + +uri="$basepath/login" + +data=$(jq --arg name $login_username --arg pass $login_password --arg dname $login_domainname --arg dtype $login_domaintype \ + --null-input '{userName: $name, password: $pass, domainName: $dname, domainType: $dtype}') + +jwt=$(curl --silent -k -X POST $uri -H $content_header -d "$data" | jq --raw-output '.token') + +##############jobs############## + +auth_header="authorization:$jwt" +content_header='content-type:application/vnd.netbackup+json; version=3.0' +uri="$basepath/security/api-keys" + +# Construct request body +request_body="{" +request_body="${request_body}\"data\": {" +request_body="${request_body}\"type\": \"apiKeyCreationRequest\"," +request_body="${request_body}\"attributes\": {" +request_body="${request_body}\"description\" : \"${description}\"," +request_body="${request_body}\"expireAfterDays\": \"P${expiryindays}D\"" +if [ $apikey_other_user == 1 ]; then + request_body="${request_body},\"userName\": \"${apikey_username}\"," + request_body="${request_body}\"userDomain\": \"${apikey_domainname}\"," + request_body="${request_body}\"userDomainType\": \"${apikey_domaintype}\"" +fi +request_body="${request_body}}}}" + +curl --silent -k -X POST "$uri" -H "$content_header" -H "$auth_header" -d "$request_body" | jq + +exit 0 diff --git a/snippets/curl/apikey_delete.sh b/snippets/curl/apikey_delete.sh new file mode 100755 index 0000000..4de0fe1 --- /dev/null +++ b/snippets/curl/apikey_delete.sh @@ -0,0 +1,104 @@ +#!/bin/sh + +#####################n##################################################### + +# This script demonstrates how to delete API key of a user (self/others). To +# delete API key for other user, a user needs to have proper permissions. + +# This script requires jq command-line JSON parser +# if your system does not have jq installed, this will not work. +# jq can be downloaded from here: https://github.com/stedolan/jq/releases + +########################################################################### + +port=1556 +master_server="" +login_username="" +login_password="" +login_domainname="" +login_domaintype="" +apikey_tag="" + +showHelp() +{ + echo "" + echo "Invalid command parameters" + echo "Usage:" + echo "./apikey_delete.sh -nbmaster -login_username -login_password -login_domainname -login_domaintype -apikey_tag " + echo "-nbmaster : Name of the NetBackup master server" + echo "-login_username : User name of the user performing action" + echo "-login_password : Password of the user performing action" + echo "-login_domainname : Domain name of the user performing action" + echo "-login_domaintype : Domain type of the user performing action" + echo "-apikey_tag : Tag associate with API key to be deleted" + echo "" + exit 1 +} + +parseArguments() +{ + if [ $# -ne 12 ]; then + showHelp + fi + + while [ "$1" != "" ]; do + case $1 in + -nbmaster) + master_server=$2 + ;; + -login_username) + login_username=$2 + ;; + -login_password) + login_password=$2 + ;; + -login_domainname) + login_domainname=$2 + ;; + -login_domaintype) + login_domaintype=$2 + ;; + -apikey_tag) + apikey_tag=$2 + ;; + *) + showHelp + ;; + esac + shift 2 + done + + if [ -z "$master_server" ] || [ -z "$login_username" ] || [ -z "$login_password" ] || [ -z "$login_domainname" ] || [ -z "$login_domaintype" ] || [ -z "$apikey_tag" ]; then + showHelp + fi + + if [ "${login_domaintype^^}" = "WINDOWS" ] || [ "${login_domaintype^^}" = "NT" ]; then + login_domaintype="nt" + fi +} + +###############main############ + +parseArguments "$@" + +basepath="https://$master_server:$port/netbackup" +content_header='content-type:application/json' + +##############login############# + +uri="$basepath/login" + +data=$(jq --arg name $login_username --arg pass $login_password --arg dname $login_domainname --arg dtype $login_domaintype \ + --null-input '{userName: $name, password: $pass, domainName: $dname, domainType: $dtype}') + +jwt=$(curl --silent -k -X POST $uri -H $content_header -d "$data" | jq --raw-output '.token') + +##############jobs############## + +auth_header="authorization:$jwt" +content_header='content-type:application/vnd.netbackup+json; version=3.0' +uri="$basepath/security/api-keys/$apikey_tag" + +curl --silent -k -X DELETE "$uri" -H "$content_header" -H "$auth_header" | jq + +exit 0 diff --git a/snippets/curl/apikey_usage.sh b/snippets/curl/apikey_usage.sh new file mode 100755 index 0000000..1406f4e --- /dev/null +++ b/snippets/curl/apikey_usage.sh @@ -0,0 +1,72 @@ +#!/bin/sh + + +#####################n##################################################### + +# This script demonstrates the usage of API key in NetBackup REST API for listing the jobs + +# This script requires jq command-line JSON parser +# if your system does not have jq installed, this will not work +# jq can be downloaded from here: https://github.com/stedolan/jq/releases + +########################################################################### + +port=1556 +master_server="" +apikey="" + +showHelp() +{ + echo "" + echo "Invalid command parameters" + echo "Usage:" + echo "./apikey_usage.sh -nbmaster -apikey " + echo "-nbmaster : Name of the NetBackup master server" + echo "-apikey : API key to be used instead of JWT" + echo "" + exit 1 +} + +parseArguments() +{ + if [ $# -lt 4 ]; then + showHelp + fi + + while [ "$1" != "" ]; do + case $1 in + -nbmaster) + master_server=$2 + ;; + -apikey) + apikey=$2 + ;; + *) + showHelp + ;; + esac + shift 2 + done + + if [ -z "$master_server" ] || [ -z "$apikey" ]; then + showhelp + fi +} + +###############main############# + +parseArguments "$@" + +basepath="https://$master_server:$port/netbackup" +content_header='content-type:application/vnd.netbackup+json; version=3.0' + +##############jobs############## + +auth_header="authorization:$apikey" +uri="$basepath/admin/jobs" + +echo "Using API key [$apikey] instead of JWT token to trigger job REST API" +curl --insecure --request GET --globoff --get "$uri" -H "$content_header" -H "$auth_header" \ + | \ + jq '[.data[]|{JOBID: .id, TYPE: .attributes.jobType, STATE: .attributes.state, STATUS: .attributes.status}]' +exit 0 diff --git a/snippets/curl/get_nb_assets.sh b/snippets/curl/get_nb_assets.sh new file mode 100644 index 0000000..b69c84a --- /dev/null +++ b/snippets/curl/get_nb_assets.sh @@ -0,0 +1,117 @@ +#!/bin/sh + +########################################################################### + +# This script demonstrates the usage of NetBackup (8.3) REST API for listing +# VMware assets. +# The script uses asset service API available from NetBackup 8.3 version. + +# This script requires jq command-line JSON parser +# if your system does not have jq installed, this will not work +# jq can be downloaded from here: https://github.com/stedolan/jq/releases + +########################################################################### + +port=1556 +master_server="" +username="" +password="" +domainname="" +domaintype="" + +showHelp() +{ + echo "" + echo "Invalid command parameters" + echo "Usage:" + echo "./get_nb_assets.sh -nbmaster -username -password -domainname -domaintype " + echo "" + exit 1 +} + +parseArguments() +{ + if [ $# -lt 6 ]; then + showHelp + fi + + while [ "$1" != "" ]; do + case $1 in + -nbmaster) + master_server=$2 + ;; + -username) + username=$2 + ;; + -password) + password=$2 + ;; + -domainname) + domainname=$2 + ;; + -domaintype) + domaintype=$2 + ;; + *) + showHelp + ;; + esac + shift 2 + done + + if [ -z "$master_server" ] || [ -z "$username" ] || [ -z "$password" ] || [ -z "$domainname" ] || [ -z "$domaintype" ]; then + showhelp + fi + + if [ "${domaintype^^}" = "WINDOWS" ] || [ "${domaintype^^}" = "NT" ]; then + domaintype="nt" + fi +} + +uriencode() +{ + jq -nr --arg v "$1" '$v|@uri'; +} +###############main############ + +parseArguments "$@" + +master_server=$master_server.$domainname +basepath="https://$master_server:$port/netbackup" +content_header='content-type:application/json' + +##############login############# + +uri="$basepath/login" +echo $uri + +data=$(jq --arg name "$username" --arg pass "$password" --arg dname "$domainname" --arg dtype "$domaintype" \ + --null-input '{userName: $name, password: $pass}') + +jwt=$(curl -k -X POST $uri -H $content_header -d "$data" | jq --raw-output '.token') + +### To use filter page[limit] in URI, The key 'page[limit]' must be url encoded already. ### +### Curl --data-urlencode encodes only the content part of the data of the form 'name=content' ### +param1="$(uriencode 'page[limit]')=10" #op: page%5Blimit%5D=10 +param2="$(uriencode 'page[offset]')=0" + + +##############jobs############## +auth_header="authorization:$jwt" +uri="$basepath/asset-service/workloads/vmware/assets" + +curl --insecure --request GET --globoff --get $uri -H $content_header -H $auth_header \ + --data-urlencode "$param1" \ + --data-urlencode "$param2" \ + | \ + jq '[.data[]|{Type: .type, ID: .id, + AssetType: .attributes.assetType, + DisplayName: .attributes.commonAssetAttributes.displayName, + HostName: .attributes.commonAssetAttributes.masters[].hostName, + UUID: .attributes.commonAssetAttributes.masters[].uuid, + DataCenter: .attributes.datacenter, + vCenter: .attributes.vCenter, + vCenterVersion: .attributes.vCenterVersion + }]' + +exit 0 diff --git a/snippets/curl/get_nb_images.sh b/snippets/curl/get_nb_images.sh index 6ea691b..0ee9e91 100755 --- a/snippets/curl/get_nb_images.sh +++ b/snippets/curl/get_nb_images.sh @@ -67,6 +67,10 @@ parseArguments() fi } +uriencode() +{ + jq -nr --arg v "$1" '$v|@uri'; +} ###############main############ parseArguments "$@" @@ -84,7 +88,10 @@ data=$(jq --arg name $username --arg pass $password --arg dname $domainname --ar jwt=$(curl -k -X POST $uri -H $content_header -d "$data" | jq --raw-output '.token') param1="filter=policyType eq 'Standard'" -param2="page[limit]=10" + +### To use filter page[limit] in URI, The key 'page[limit]' must be url encoded already. ### +### Curl --data-urlencode encodes only the content part of the data of the form 'name=content' ### +param2="$(uriencode 'page[limit]')=10" #op: page%5Blimit%5D=10 ##############jobs############## diff --git a/snippets/curl/get_nb_jobs.sh b/snippets/curl/get_nb_jobs.sh index 0ab4562..4622890 100755 --- a/snippets/curl/get_nb_jobs.sh +++ b/snippets/curl/get_nb_jobs.sh @@ -67,6 +67,11 @@ parseArguments() fi } +uriencode() +{ + jq -nr --arg v "$1" '$v|@uri'; +} + ###############main############# parseArguments "$@" @@ -84,7 +89,10 @@ data=$(jq --arg name $username --arg pass $password --arg dname $domainname --ar jwt=$(curl -k -X POST $uri -H $content_header -d "$data" | jq --raw-output '.token') param1="filter=jobType eq 'BACKUP'" -param2="page[limit]=10" + +### To use filter page[limit] in URI, The key 'page[limit]' must be url encoded already. ### +### Curl --data-urlencode encodes only the content part of the data of the form 'name=content' ### +param2="$(uriencode 'page[limit]')=10" #op: page%5Blimit%5D=10 ##############jobs############## diff --git a/snippets/curl/get_nb_vmservers.sh b/snippets/curl/get_nb_vmservers.sh new file mode 100644 index 0000000..a7c6db4 --- /dev/null +++ b/snippets/curl/get_nb_vmservers.sh @@ -0,0 +1,111 @@ +#!/bin/sh + +#####################n##################################################### + +# This script demonstrates the usage of netbackup REST API for listing +# the vmservers + +# This script requires jq command-line JSON parser +# if your system does not have jq installed, this will not work +# jq can be downloaded from here: https://github.com/stedolan/jq/releases + +########################################################################### + +port=1556 +master_server="" +username="" +password="" +domainname="" +domaintype="" + +showHelp() +{ + echo "" + echo "Invalid command parameters" + echo "Usage:" + echo "./get_nb_vmservers.sh -nbmaster -username -password -domainname -domaintype " + echo "" + exit 1 +} + +parseArguments() +{ + if [ $# -lt 6 ]; then + showHelp + fi + + while [ "$1" != "" ]; do + case $1 in + -nbmaster) + master_server=$2 + ;; + -username) + username=$2 + ;; + -password) + password=$2 + ;; + -domainname) + domainname=$2 + ;; + -domaintype) + domaintype=$2 + ;; + *) + showHelp + ;; + esac + shift 2 + done + + if [ -z "$master_server" ] || [ -z "$username" ] || [ -z "$password" ] || [ -z "$domainname" ] || [ -z "$domaintype" ]; then + showhelp + fi + + if [ "${domaintype^^}" = "WINDOWS" ] || [ "${domaintype^^}" = "NT" ]; then + domaintype="nt" + fi +} + +uriencode() +{ + jq -nr --arg v "$1" '$v|@uri'; +} +###############main############ + +parseArguments "$@" + +master_server=$master_server.$domainname +basepath="https://$master_server:$port/netbackup" +content_header='content-type:application/json' + +##############login############# + +uri="$basepath/login" +echo $uri + +data=$(jq --arg name "$username" --arg pass "$password" --arg dname "$domainname" --arg dtype "$domaintype" \ + --null-input '{userName: $name, password: $pass}') + +jwt=$(curl -k -X POST $uri -H $content_header -d "$data" | jq --raw-output '.token') + +### To use filter page[limit] in URI, The key 'page[limit]' must be url encoded already. ### +### Curl --data-urlencode encodes only the content part of the data of the form 'name=content' ### +param1="$(uriencode 'page[limit]')=10" #op: page%5Blimit%5D=10 +param2="$(uriencode 'page[offset]')=0" + + +##############jobs############## +auth_header="authorization:$jwt" +uri="$basepath/config/servers/vmservers" + +curl --insecure --request GET --globoff --get $uri -H $content_header -H $auth_header \ + --data-urlencode "$param1" \ + --data-urlencode "$param2" \ + | \ + jq '[.data[]|{Type: .type, ID: .id, + ServerName: .attributes.vmServer.serverName, + VmType: .attributes.vmServer.vmType, + UserId: .attributes.vmServer.userId}]' + +exit 0 diff --git a/snippets/go/README.md b/snippets/go/README.md new file mode 100644 index 0000000..3e42425 --- /dev/null +++ b/snippets/go/README.md @@ -0,0 +1,28 @@ +# NetBackup package for GO language + +This package gives a wrapper to call NetBackup APIs. +There are few raw functions that can be used generically to +call NetBackup APIs. +There are also some specific call that creates the URL, calls the API, parse the output and return back the data. + + +## Building and executing sample program +Pre-requisites: +- NetBackup 8.1.1 or higher +- Go version 1.10.2 + +Use the following commands to build and execute the sample program +```sh +$ cd netbackup +$ # Build sample program for fetching server mappings +$ go build example/get_nb_mapping.go +$ ./get_nb_mapping + +$ # Build sample program for fetching catalog images +$ go build example/get_nb_images.go +$ ./get_nb_images + +$ # Build sample program for fetching backup jobs +$ go build example/get_nb_jobs.go +$ ./get_nb_jobs +``` diff --git a/snippets/go/example/get_nb_images.go b/snippets/go/example/get_nb_images.go new file mode 100644 index 0000000..cd60215 --- /dev/null +++ b/snippets/go/example/get_nb_images.go @@ -0,0 +1,34 @@ +package main + import ( + "bufio" + "fmt" + "netbackup" + "os" +) + func main() { + fmt.Printf("Welcome to sample Go program to call NetBackup APIs\n") + scanner := bufio.NewScanner(os.Stdin) + fmt.Printf("Enter the server to connect: ") + scanner.Scan() + server := scanner.Text() + fmt.Printf("Enter username for server:") + scanner.Scan() + username := scanner.Text() + fmt.Printf("Enter password for server:") + scanner.Scan() + password := scanner.Text() + fmt.Printf("Enter domain name for server:") + scanner.Scan() + domain := scanner.Text() + fmt.Printf("Enter domain type :") + scanner.Scan() + domainType := scanner.Text() + fmt.Printf("Calling NetBackup Login\n") + fmt.Printf("-----------------------\n") + jwt := netbackup.Login(username, password, domain, domainType, server) + fmt.Printf("-----------------------\n") + fmt.Printf("Netbackup Images List using jwt\n") + fmt.Printf("-----------------------\n") + netbackup.ImagesList(jwt, server) + fmt.Printf("-----------------------\n") +} diff --git a/snippets/go/example/get_nb_jobs.go b/snippets/go/example/get_nb_jobs.go new file mode 100644 index 0000000..d394510 --- /dev/null +++ b/snippets/go/example/get_nb_jobs.go @@ -0,0 +1,34 @@ +package main + import ( + "bufio" + "fmt" + "netbackup" + "os" +) + func main() { + fmt.Printf("Welcome to sample Go program to call NetBackup APIs\n") + scanner := bufio.NewScanner(os.Stdin) + fmt.Printf("Enter the server to connect: ") + scanner.Scan() + server := scanner.Text() + fmt.Printf("Enter username for server:") + scanner.Scan() + username := scanner.Text() + fmt.Printf("Enter password for server:") + scanner.Scan() + password := scanner.Text() + fmt.Printf("Enter domain name for server:") + scanner.Scan() + domain := scanner.Text() + fmt.Printf("Enter domain type :") + scanner.Scan() + domainType := scanner.Text() + fmt.Printf("Calling NetBackup Login\n") + fmt.Printf("-----------------------\n") + jwt := netbackup.Login(username, password, domain, domainType, server) + fmt.Printf("-----------------------\n") + fmt.Printf("Netbackup Jobs List using jwt\n") + fmt.Printf("-----------------------\n") + netbackup.JobList(jwt, server) + fmt.Printf("-----------------------\n") +} diff --git a/snippets/go/example/get_nb_mappings.go b/snippets/go/example/get_nb_mappings.go new file mode 100644 index 0000000..3d80442 --- /dev/null +++ b/snippets/go/example/get_nb_mappings.go @@ -0,0 +1,38 @@ +package main + import ( + "bufio" + "fmt" + "netbackup" + "os" +) + func main() { + fmt.Printf("Welcome to sample Go program to call NetBackup APIs\n") + scanner := bufio.NewScanner(os.Stdin) + fmt.Printf("Enter the server to connect: ") + scanner.Scan() + server := scanner.Text() + fmt.Printf("Checking connectivity with NetBackup Server[%s]\n", server) + fmt.Printf("-----------------------\n") + fmt.Println(netbackup.Ping(server)) + fmt.Printf("-----------------------\n") + fmt.Printf("Enter username for server:") + scanner.Scan() + username := scanner.Text() + fmt.Printf("Enter password for server:") + scanner.Scan() + password := scanner.Text() + fmt.Printf("Enter domain name for server:") + scanner.Scan() + domain := scanner.Text() + fmt.Printf("Enter domain type :") + scanner.Scan() + domainType := scanner.Text() + fmt.Printf("Calling NetBackup Login\n") + fmt.Printf("-----------------------\n") + jwt := netbackup.Login(username, password, domain, domainType, server) + fmt.Printf("-----------------------\n") + fmt.Printf("Mapping List using jwt\n") + fmt.Printf("-----------------------\n") + netbackup.MappingList(jwt, server) + fmt.Printf("-----------------------\n") +} diff --git a/snippets/go/netbackup.go b/snippets/go/netbackup.go new file mode 100644 index 0000000..860e295 --- /dev/null +++ b/snippets/go/netbackup.go @@ -0,0 +1,245 @@ +// Package netbackup provides functions for calling netbackup APIs and +// get there response back in structured formata. +package netbackup + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" +) + +// NetBackup structure to directly call raw APIs +// or some predefined APIs +type NetBackup struct { + jwt string + baseURL string + skipVerification bool +} + +// ---------------------------------------- +// +// Raw functions to call APIs and their helper functions +// +// ---------------------------------------- + +// Get Raw function to call any GET APIs of NetBackup +func Get(jwt string, url string) (jsonData map[string]interface{}, code int, err error) { + + client := getHTTPClient() + req, err := http.NewRequest("GET", url, nil) + if jwt != "" { + req.Header.Add("Authorization", jwt) + } + req.Header.Add("ContentType", "application/vnd.netbackup+json; version=1.0") + + response, err := client.Do(req) + if err == nil { + code = response.StatusCode + if code >= 200 && code <= 299 { + data, _ := ioutil.ReadAll(response.Body) + if err := json.Unmarshal(data, &jsonData); err != nil { + panic(err) + } + } + } + defer response.Body.Close() + return jsonData, response.StatusCode, err +} + +// Post Raw function to call any POST APIs of NetBackup +func Post(jwt string, url string, reqValue []byte) (jsonData map[string]interface{}, code int, err error) { + + client := getHTTPClient() + req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqValue)) + if jwt != "" { + req.Header.Add("Authorization", jwt) + } + req.Header.Add("Content-Type", "application/vnd.netbackup+json; version=1.0") + response, err := client.Do(req) + + if err == nil { + code = response.StatusCode + if code >= 200 && code <= 299 { + resData, _ := ioutil.ReadAll(response.Body) + if err := json.Unmarshal(resData, &jsonData); err != nil { + panic(err) + } + } + } + defer response.Body.Close() + return jsonData, code, err +} + +// ---------------------------------------- +// +// Some additional functions that you can directly call to +// achieve some basic functionality. +// +// ---------------------------------------- + +// Ping function call the netbackup ping API. This can be used +// to check the connectivity to Master server web services +func Ping(server string) string { + var data []byte + url := GetBaseURLString(server) + "/ping" + client := getHTTPClient() + response, err := client.Get(url) + if err != nil { + fmt.Printf("Request Failed %s \n", err) + } else { + data, _ = ioutil.ReadAll(response.Body) + return (string(data)) + } + return (string("")) +} + +//Login function +func Login(username string, password string, domain string, domainType string, server string) string { + url := GetBaseURLString(server) + "/login" + reqData := map[string]string{"userName": username, "password": password, "domainName": domain, "domainType": domainType} + reqValue, _ := json.Marshal(reqData) + + jsonData, code, err := Post("", url, reqValue) + + if err != nil { + fmt.Printf("Request Failed %s \n", err) + } else { + fmt.Println(code) + if code != 201 { + fmt.Printf("Wrong response %d \n", code) + return "" + } + } + fmt.Printf("Login succesful. got jwt[%s]", jsonData["token"].(string)) + return jsonData["token"].(string) +} + +// MappingList Returns list of mappings for the server in JSON format +func MappingList(jwt string, server string) { + url := GetBaseURLString(server) + "/config/hosts" + + jsonData, code, err := Get(jwt, url) + if err != nil { + fmt.Printf("Request Failed %s \n", err) + } else { + if code != 200 { + fmt.Printf("Request returned wrong code %d \n", code) + return + } + } + fmt.Println(jsonData) +} + +// ImagesList API Returns list of catalog images +func ImagesList(jwt string, server string) { + + url := GetBaseURLString(server) + "/catalog/images" + + client := getHTTPClient() + req, err := http.NewRequest("GET", url, nil) + if jwt != "" { + req.Header.Add("Authorization", jwt) + } + req.Header.Add("ContentType", "application/vnd.netbackup+json; version=1.0") + + //Adding filters in query string + q := req.URL.Query() + q.Add("filter", "policyType eq 'Standard'") + q.Add("page[limit]", "10") + req.URL.RawQuery = q.Encode() + + var jsonData map[string]interface{} + + response, err := client.Do(req) + if err == nil { + if response.StatusCode >= 200 && response.StatusCode <= 299 { + data, _ := ioutil.ReadAll(response.Body) + if err := json.Unmarshal(data, &jsonData); err != nil { + panic(err) + } + } + } + defer response.Body.Close() + + if err != nil { + fmt.Printf("Request Failed %s \n", err) + } else { + if response.StatusCode != 200 { + fmt.Printf("Request returned wrong code %d \n", response.StatusCode) + return + } + } + + b, err := json.MarshalIndent(jsonData, "", " ") + if err != nil { + fmt.Println("error:", err) + } + os.Stdout.Write(b) +} + +// JobList API Returns list of backup jobs +func JobList(jwt string, server string) { + url := GetBaseURLString(server) + "/admin/jobs" + + client := getHTTPClient() + req, err := http.NewRequest("GET", url, nil) + if jwt != "" { + req.Header.Add("Authorization", jwt) + } + req.Header.Add("ContentType", "application/vnd.netbackup+json; version=1.0") + + //Adding filters in query string + q := req.URL.Query() + q.Add("filter", "jobType eq 'BACKUP'") + q.Add("page[limit]", "10") + req.URL.RawQuery = q.Encode() + + var jsonData map[string]interface{} + + response, err := client.Do(req) + if err == nil { + if response.StatusCode >= 200 && response.StatusCode <= 299 { + data, _ := ioutil.ReadAll(response.Body) + if err := json.Unmarshal(data, &jsonData); err != nil { + panic(err) + } + } + } + defer response.Body.Close() + + if err != nil { + fmt.Printf("Request Failed %s \n", err) + } else { + if response.StatusCode != 200 { + fmt.Printf("Request returned wrong code %d \n", response.StatusCode) + return + } + } + + b, err := json.MarshalIndent(jsonData, "", " ") + if err != nil { + fmt.Println("error:", err) + } + os.Stdout.Write(b) +} + +// GetBaseURLString This returns the base URL for netbackup +func GetBaseURLString(server string) string { + return "https://" + server + ":1556/netbackup" +} + +func getContentType() string { + return "application/vnd.netbackup+json; version=1.0" +} + +func getHTTPClient() http.Client { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client := &http.Client{Transport: tr} + return *client +} diff --git a/snippets/perl/README.md b/snippets/perl/README.md index fa9549b..56b1fa8 100644 --- a/snippets/perl/README.md +++ b/snippets/perl/README.md @@ -9,6 +9,7 @@ These scripts are only meant to be used as a reference. If you intend to use the #### Pre-requisites: - NetBackup 8.1.1 or higher +- NetBackup 8.2 or higher for using API keys related APIs and samples - Perl v5.18.2 - Perl modules Text::Table, JSON and LWP @@ -80,3 +81,58 @@ no a subscription associated with this asset. - Example: perl post_nb_asset_cleanup.pl -nbmaster -username -password -filter "workloadType eq 'VMware'" -cleanuptime 2018-06-29T15:58:45.678Z +#### Scripts for NetBackup 8.2 or higher + +VM Servers Details: + +- Use the following command to obtain the list of all VM servers details from your NetBackup Master server: + - `perl get_vm_servers.pl -nbmaster -username -password [-domainname ] [-domaintype ] [--verbose]` + +VM Server Details: + +- Use the following command to obtain the VM server details from your NetBackup Master server: + - `perl get_vm_server.pl -nbmaster -username -password -servername [-domainname ] [-domaintype ] [--verbose]` + +NetBackup All Resource Limits: + +- Use the following command to obtain the list of all NetBackup resource limits from your NetBackup Master server: + - `perl get_all_resource_limits.pl -nbmaster -username -password [-domainname ] [-domaintype ] [--verbose]` + +NetBackup Resource Limits: + +- Use the following command to obtain the NetBackup resource limits from your NetBackup Master server: + - `perl get_resource_limits.pl -nbmaster -username -password -workloadtype [-domainname ] [-domaintype ] [--verbose]` + +NetBackup All Resource Limits Templates: + +- Use the following command to obtain the list of all NetBackup resource limits templates from your NetBackup Master server: + - `perl get_all_resource_limits_templates.pl -nbmaster -username -password [-domainname ] [-domaintype ] [--verbose]` + +NetBackup Resource Limits Template: + +- Use the following command to obtain the NetBackup resource limits template from your NetBackup Master server: + - `perl get_resource_limits_template.pl -nbmaster -username -password -workloadtype [-domainname ] [-domaintype ] [--verbose]` + +API key Details: + +- Use the following command to create an API key for yourself on your NetBackup Master server: + - `perl apikey_create.pl -nbmaster -login_username -login_password [-login_domainname -login_domaintype ] -expiryindays -description [--verbose]` + +- Use the following command to create an API key for other user on your NetBackup Master server: + - `perl apikey_create.pl -nbmaster -login_username -login_password [-login_domainname -login_domaintype ] -apikey_username -apikey_domainname -apikey_domaintype -expiryindays -description [--verbose]` + +- Use the following command to delete an API key on your NetBackup Master server with apikey tag provided: + - `perl apikey_delete.pl -nbmaster -login_username -login_password [-login_domainname -login_domaintype ] -apikey_tag [--verbose]` + +- Use the following command to use API key instead of JWT to trigger a NetBackup REST API on your NetBackup Master server: + - `perl apikey_usage.pl -nbmaster -apikey [--verbose]` + +#### Scripts for NetBackup 8.3 or higher + +NetBackup Event Log Notifications: + +- Use the following command to obtain the top 10 NetBackup notifications in descending order of their creation time. + - `perl get_notifications.pl -nbmaster -username -password [-domainname ] [-domaintype ] [-filter ] [--verbose]` + +- Use the following command to post notifications to the event log database. + - `perl post_notifications.pl -nbmaster -username -password [-domainname ] [-domaintype ] [-payload ] [--verbose]` diff --git a/snippets/perl/apikey_create.pl b/snippets/perl/apikey_create.pl new file mode 100644 index 0000000..a693196 --- /dev/null +++ b/snippets/perl/apikey_create.pl @@ -0,0 +1,110 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use strict; +use warnings; + +use Getopt::Long qw(GetOptions); + +use netbackup; +use apikeys; + +sub printUsage { + print "\nUsage : perl apikey_create.pl -nbmaster -login_username -login_password [-login_domainname -login_domaintype ] [-apikey_username -apikey_domainname -apikey_domaintype ] -expiryindays -description [--verbose]\n\n"; + print "-nbmaster : Name of the NetBackup master server\n"; + print "-login_username : User name of the user performing action\n"; + print "-login_password : Password of the user performing action\n"; + print "-login_domainname : Domain name of the user performing action\n"; + print "-login_domaintype : Domain type of the user performing action\n"; + print "-apikey_username : (Optional) User name of the user for whom API key needs to be generated. Optional in case API key is to be generated for self\n"; + print "-apikey_domainname : Domain name of the user for whom API key needs to be generated. Optional in case API key is to be generated for self\n"; + print "-apikey_domaintype : Domain type of the user for whom API key needs to be generated. Optional in case API key is to be generated for self\n"; + print "-expiryindays : Number of days from today after which API key should expire\n"; + print "-description : A textual description to be associated with API key\n"; + print "--verbose : Detail logging\n\n\n"; + die; +} + +my $fqdn_hostname; +my $login_username; +my $login_password; +my $login_domainname; +my $login_domaintype; +my $apikey_username; +my $apikey_domainname; +my $apikey_domaintype; +my $verbose; +my $expiryindays; +my $description; + +GetOptions( + 'nbmaster=s' => \$fqdn_hostname, + 'login_username=s' => \$login_username, + 'login_password=s' => \$login_password, + 'login_domainname=s' => \$login_domainname, + 'login_domaintype=s' => \$login_domaintype, + 'apikey_username=s' => \$apikey_username, + 'apikey_domainname=s' => \$apikey_domainname, + 'apikey_domaintype=s' => \$apikey_domaintype, + 'expiryindays=s' => \$expiryindays, + 'description=s' => \$description, + 'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$login_username || !$login_password || !$expiryindays || !$description) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Login Username : $login_username\n"; + print " Login Password : $login_password\n"; + print " Login Domain Name : $login_domainname\n" if (defined $login_domainname); + print " Login Domain Type : $login_domaintype\n" if (defined $login_domaintype); + print " API Key Username : $apikey_username\n" if (defined $apikey_username); + print " API Key Domain Name : $apikey_domainname\n" if (defined $apikey_domainname); + print " API Key Domain Type : $apikey_domaintype\n" if (defined $apikey_domaintype); + print " Expiry period in days : $expiryindays\n"; + print " Description : $description\n"; +} + +print "\nLogging in to NetBackup using user-credentials of user [$login_username]\n" if($verbose); +my $token; +if (defined $login_domainname && defined $login_domaintype) { + $token = netbackup::login($fqdn_hostname, $login_username, $login_password, $login_domainname, $login_domaintype); +} +else{ + $token = netbackup::login($fqdn_hostname, $login_username, $login_password); +} + +if(!defined $token) { + print "\nFailed to login using credentials provided for user [$login_username]\n"; + exit -1; +} +print "\nSuccessfully acquired auth-token" if($verbose); + +my($apikey, $apikey_tag, $apikey_expiry); +my $is_success = 0; +if (defined $apikey_username and defined $apikey_domainname and defined $apikey_domaintype) { + print "\nUser [$login_username] creating API key for user [$apikey_username]" if($verbose); + $is_success = apikeys::create_apikey($fqdn_hostname, $token, $expiryindays, $description, \$apikey, \$apikey_tag, \$apikey_expiry, $apikey_username, $apikey_domainname, $apikey_domaintype); +} +else { + print "\n [$login_username] creating API key for self" if($verbose); + $is_success = apikeys::create_apikey($fqdn_hostname, $token, $expiryindays, $description, \$apikey, \$apikey_tag, \$apikey_expiry); +} +if (!$is_success) { + print "\nFailed to create API key\n"; + exit -1; +} +print "\nSuccessfully created API key" if($verbose); + +print "\nAPI Key : [" . $apikey . "]"; +print "\nAPI Key Tag : [" . $apikey_tag . "]"; +print "\nAPI Key Expiration : [" . $apikey_expiry. "]"; + +netbackup::logout($fqdn_hostname, $token); +print "\n"; + +exit 0; diff --git a/snippets/perl/apikey_delete.pl b/snippets/perl/apikey_delete.pl new file mode 100644 index 0000000..be9b6c3 --- /dev/null +++ b/snippets/perl/apikey_delete.pl @@ -0,0 +1,82 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use strict; +use warnings; + +use Getopt::Long qw(GetOptions); + +use netbackup; +use apikeys; + +sub printUsage { + print "\nUsage : perl apikey_delete.pl -nbmaster -login_username -login_password [-login_domainname -login_domaintype ] -apikey_tag [--verbose]\n"; + print "-nbmaster : Name of the NetBackup master server\n"; + print "-login_username : User name of the user performing action\n"; + print "-login_password : Password of the user performing action\n"; + print "-login_domainname : Domain name of the user performing action\n"; + print "-login_domaintype : Domain type of the user performing action\n"; + print "-apikey_tag : Tag associate with API key to be deleted\n"; + print "--verbose : Detail logging\n\n\n"; + die; +} + +my $fqdn_hostname; +my $login_username; +my $login_password; +my $login_domainname; +my $login_domaintype; +my $apikey_tag; +my $verbose; + +GetOptions( + 'nbmaster=s' => \$fqdn_hostname, + 'login_username=s' => \$login_username, + 'login_password=s' => \$login_password, + 'login_domainname=s' => \$login_domainname, + 'login_domaintype=s' => \$login_domaintype, + 'apikey_tag=s' => \$apikey_tag, + 'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$login_username || !$login_password || !$apikey_tag) { + printUsage(); +} + +if($verbose){ + print "\nReceived the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Login Username : $login_username\n"; + print " Login Password : $login_password\n"; + print " Login Domain Name : $login_domainname\n" if (defined $login_domainname); + print " Login Domain Type : $login_domaintype\n" if (defined $login_domaintype); + print " API Key Tag to be deleted : $apikey_tag\n"; +} + +print "\nLogging in to NetBackup using user-credentials of user [$login_username]\n" if($verbose); +my $token; +if (defined $login_domainname && defined $login_domaintype) { + $token = netbackup::login($fqdn_hostname, $login_username, $login_password, $login_domainname, $login_domaintype); +} +else{ + $token = netbackup::login($fqdn_hostname, $login_username, $login_password); +} + +if(!defined $token) { + print "\nFailed to login using credentials provided for user [$login_username]\n"; + exit -1; +} +print "\nSuccessfully acquired auth-token" if($verbose); + +print "\nUser [$login_username] deleting API key with tag [$apikey_tag]" if($verbose); +my $is_success = apikeys::delete_apikey($fqdn_hostname, $token, $apikey_tag); +if (!$is_success) { + print "\nFailed to delete API key with tag [$apikey_tag]\n"; + exit -1; +} +print "\nSuccessfully deleted API key" if($verbose); + +netbackup::logout($fqdn_hostname, $token); +print "\n"; + +exit 0; diff --git a/snippets/perl/apikey_usage.pl b/snippets/perl/apikey_usage.pl new file mode 100644 index 0000000..35284d7 --- /dev/null +++ b/snippets/perl/apikey_usage.pl @@ -0,0 +1,45 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use netbackup; +use strict; +use warnings; +use Getopt::Long qw(GetOptions); + +sub printUsage { + print "\nUsage : perl apikey_usage.pl -nbmaster -apikey [--verbose]\n"; + print "-nbmaster : Name of the NetBackup master server\n"; + print "-apikey : API key to be used instead of JWT"; + print "--verbose : Detail logging\n\n"; + die; +} + +my $fqdn_hostname; +my $apikey; +my $verbose; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'apikey=s' => \$apikey, +'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$apikey) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " API key : $apikey\n"; +} +print "\n"; + +print "\nUsing API key [$apikey] instead of JWT token to trigger job REST API\n\n"; +my $jsonstring = netbackup::getJobs($fqdn_hostname, $apikey); + +print "\nNetBackup Jobs:\n"; +netbackup::displayJobs($jsonstring); + +netbackup::logout($fqdn_hostname, $apikey); +print "\n"; diff --git a/snippets/perl/apikeys.pm b/snippets/perl/apikeys.pm new file mode 100644 index 0000000..e6e0105 --- /dev/null +++ b/snippets/perl/apikeys.pm @@ -0,0 +1,195 @@ +package apikeys; + +use strict; +use warnings; + +use JSON; +use LWP::UserAgent; +use LWP::Protocol::https; + +# constants +my $APIKEY_URL = "/netbackup/security/api-keys"; +my $APIKEY_NB_CONTENT_TYPE_V3 = "application/vnd.netbackup+json; version=3.0"; +my $SUCCESS = 1; +my $FAILURE = 0; + +=head1 create_apikey + + SYNOPSIS + This subroutine is used to call /security/api-keys api to create apikey + for self or a user specified + + PARAMETERS + @param $_[0] - string + The name of the master server. + Ex: myhostname.myDomain.com + @param $_[1] - string + The authentication token fetched after invoking /login api using + user credentials or apikey. + @param $_[2] - int + The expiration period in days from today. + @param $_[3] - string + The description to be associated with api-key + @param $_[4] - scalarRef + Reference variable to hold apikey value generated. + @param $_[5] - scalarRef + Reference variable to hold apikey tag value. + @param $_[6] - scalarRef + Reference variable to hold apikey expiration date-time value. + @param $_[7] - string - optional + The username of the user whose api key needs to be generated. If not + specified, api key will be created for the user whose token is mentioned + in the paramater to this function. + Either mention username, domainname and domaintype or provide none. + @param $_[8] - string - optional + The domain in which the user belongs. + Either mention username, domainname and domaintype or provide none. + @param $_[9] - string - optional + The domain type of the user. + Either mention username, domainname and domaintype or provide none. + + RETURNS + 1 - SUCCESS, 0 - FAILURE + +=cut +sub create_apikey { + my @argument_list = @_; + my $master_server = $argument_list[0]; + my $token = $argument_list[1]; + my $expiry_in_days = $argument_list[2]; + my $description = $argument_list[3]; + my $apikey_ref = $argument_list[4]; + my $apikey_tag_ref = $argument_list[5]; + my $apikey_expiration_ref = $argument_list[6]; + + # Validate arguement count to the function + if (@argument_list != 7 and @argument_list != 10) { + print "ERROR :: Incorrect number of arguments passed to create_apikey()\n"; + print "Usage : create_apikey( , , , , , , [, , , ] ) \n"; + return $FAILURE; + } + + # user_name, domain_name and domain_type are optional + my($user_name, $domain_name, $domain_type); + if (@argument_list == 10) { + $user_name = $argument_list[7]; + $domain_name = $argument_list[8]; + $domain_type = $argument_list[9]; + } + + # Construct url + my $url = "https://$master_server:1556" . $APIKEY_URL; + + # Construct request body + my $request_body = "{" + . "\"data\": {" + . "\"type\": \"apiKeyCreationRequest\"," + . "\"attributes\": {" + . "\"description\" : \"" . $description . "\"," + . "\"expireAfterDays\": \"P" . $expiry_in_days . "D\""; + + if (@argument_list == 10) { + $request_body = $request_body + . ",\"userName\": \"" . $user_name . "\"," + . "\"userDomain\": \"" . $domain_name . "\"," + . "\"userDomainType\": \"" . $domain_type . "\""; + } + + $request_body = $request_body + . "}" + . "}" + . "}"; + + + + my $request = HTTP::Request->new(POST => $url); + $request->header('Authorization' => $token); + $request->header('content-type' => $APIKEY_NB_CONTENT_TYPE_V3); + $request->content($request_body); + + my $ua = LWP::UserAgent->new( + timeout => 500, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "\nCreating API key"; + my $response = $ua->request($request); + if (!$response->is_success) { + print "\n API request failed"; + return $FAILURE; + + } + my $response_content = decode_json($response->content); + if ($response->code != 201) { + print "API key creation failed with HTTP code [" . $response->code . "].\n"; + print "Response: " . $response->content . " \n"; + return $FAILURE; + } + print "\nSuccessfully created API key."; + + $$apikey_ref = $response_content->{"data"}{"attributes"}{"apiKey"}; + $$apikey_tag_ref = $response_content->{"data"}{"id"}; + $$apikey_expiration_ref = $response_content->{"data"}{"attributes"}{"expiryDateTime"}; + + return $SUCCESS; +} + +=head1 delete_apikey + + SYNOPSIS + This subroutine is used to call /security/api-keys api to delete apikey + with apikey tag specified + + PARAMETERS + @param $_[0] - string + The name of the master server. + Ex: myhostname.myDomain.com + @param $_[1] - string + The authentication token fetched after invoking /login api using + user credentials or apikey. + @param $_[2] - int + The API key tag of the API key to be deleted. + + RETURNS + 1 - SUCCESS, 0 - FAILURE + +=cut +sub delete_apikey { + my @argument_list = @_; + my $master_server = $argument_list[0]; + my $token = $argument_list[1]; + my $apikey_tag = $argument_list[2]; + + # Validate arguement count to the function + if (@argument_list != 3) { + print "ERROR :: Incorrect number of arguments passed to delete_apikey()\n"; + print "Usage : delete_apikey( , , ) \n"; + return $FAILURE; + } + + # Construct url + my $url = "https://$master_server:1556" . $APIKEY_URL . "/" . $apikey_tag; + + my $request = HTTP::Request->new(DELETE => $url); + $request->header('Authorization' => $token); + $request->header('content-type' => $APIKEY_NB_CONTENT_TYPE_V3); + + my $ua = LWP::UserAgent->new( + timeout => 500, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "\nDeleting API key"; + my $response = $ua->request($request); + + if ($response->code != 204) { + print "\nAPI key deletion failed with HTTP code [" . $response->code . "].\n"; + print "\nResponse: " . $response->content . " \n"; + return $FAILURE; + } + print "\nSuccessfully deleted API key."; + + return $SUCCESS; +} + +1; diff --git a/snippets/perl/eventlogs/eventlogs.pm b/snippets/perl/eventlogs/eventlogs.pm new file mode 100644 index 0000000..368fe06 --- /dev/null +++ b/snippets/perl/eventlogs/eventlogs.pm @@ -0,0 +1,195 @@ +#!/usr/bin/env perl + +package eventlogs; + +use JSON; +use warnings; +use Text::Table; +use LWP::UserAgent; +use LWP::Protocol::https; + +$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0; +$CONTENT_TYPE_V4 = "application/vnd.netbackup+json; version=4.0"; +$NB_PORT = 1556; + +# +# This function displays data in a tabular form. It takes table title array and +# table data (2-d matrix) as inputs and renders it in a tabular form with border +# +sub displayDataInTable { + + my $arguments_count = scalar(@_); + if ($arguments_count != 2) { + print "ERROR :: Incorrect number of arguments passed to displayDataInTable()\n"; + print "Usage : displayDataInTable( , ) \n"; + return; + } + + my @titletext = @{$_[0]}; + my @data = @{$_[1]}; + + my @tabletitle; + my $val; + foreach $val (@titletext) { + push @tabletitle, {is_sep => 1, title => '| ', body => '| '}; + push @tabletitle, $val; + } + push @tabletitle, {is_sep => 1, title => '| ', body => '| '}; + + my $tb = Text::Table->new( @tabletitle ); + $tb->load(@data); + + print $tb->rule('-', '+'); + for (0 .. @data) { + print $tb->table($_); + print $tb->rule('-', '+'); + } + +} + + +# +# This function returns a list of notifications based on +# a filter parameter +# + +sub getNotificationsByFilter { + + my $arguments_count = scalar(@_); + my $fqdn_hostname; + my $token; + my $filter; + + if ($arguments_count == 2) { + $fqdn_hostname = $_[0]; + $token = $_[1]; + } elsif ($arguments_count == 3) { + $fqdn_hostname = $_[0]; + $token = $_[1]; + $filter = $_[2]; + } else { + print "ERROR :: Incorrect number of arguments passed to getNotificationsByFilter()\n"; + print "Usage : getNotificationsByFilter( , . (optional) ) \n"; + return; + } + + my $url; + if ($filter) { + $url = "https://$fqdn_hostname:$NB_PORT/netbackup/eventlog/notifications?filter=$filter"; + } else { + $url = "https://$fqdn_hostname:$NB_PORT/netbackup/eventlog/notifications"; + } + + my $notifications_req = HTTP::Request->new(GET => $url); + $notifications_req->header('Authorization' => $token); + + my $ua = LWP::UserAgent->new( + timeout => 1000, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "Performing Get Notifications Request on $url\n"; + my $response = $ua->request($notifications_req); + if ($response->is_success) { + print "Successfully completed Get Notifications Request.\n"; + + $data = decode_json($response->content); + my $pretty = JSON->new->pretty->encode($data); + return $pretty; + } else { + print "ERROR :: Get Notifications Request Failed!\n"; + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + } + +} + +# +## This function displays the JSON content returned from GET Notifications API +## using query filter in a tabular format +## +sub displayNotifications { + + my $arguments_count = scalar(@_); + if ($arguments_count != 1) { + print "ERROR :: Incorrect number of arguments passed to displayNotifications()\n"; + print "Usage : displayNotifications( ) \n"; + return; + } + + my $jsonstring = $_[0]; + my $json = decode_json($jsonstring); + my @notifications = @{$json->{'data'}}; + + my @tablerows; + + foreach (@notifications) { + my $notification = $_; + + my $type = $notification->{'type'}; + my $id = $notification->{'id'}; + my $version = $notification->{'attributes'}->{'version'}; + my $priority = $notification->{'attributes'}->{'priority'}; + my $severity = $notification->{'attributes'}->{'severity'}; + my $createdDateTime = $notification->{'attributes'}->{'createdDateTime'}; + my $insertionDateTime = $notification->{'attributes'}->{'insertionDateTime'}; + my $displayString = $notification->{'attributes'}->{'displayString'}; + my $notificationType = $notification->{'attributes'}->{'notificationType'}; + my $producerName = $notification->{'attributes'}->{'producerName'}; + my $producerId = $notification->{'attributes'}->{'producerId'}; + my $producerType = $notification->{'attributes'}->{'producerType'}; + my $producerSubType = $notification->{'attributes'}->{'producerSubType'}; + my $namespace = $notification->{'attributes'}->{'namespace'}; + + my @tablerow = ($type, $id, $version, $priority, $severity, $createdDateTime, $insertionDateTime, $displayString, + $notificationType, $producerName, $producerId, $producerType, + $producerSubType, $namespace); + push @tablerows, \@tablerow; + } + + my @title = ("Type", "ID", "Version", "Priority", "Severity", "Created Date Time", "Insertion Date Time", + "Display String", "Notification Type", "Producer Name", "Producer ID", "Producer Type", + "Producer Sub Type", "Namespace"); + print "\n"; + displayDataInTable(\@title, \@tablerows); + print "\n"; + +} + +# Post notifications +sub postNotifications { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to postNotifications()\n"; + print "Usage : postNotifications( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $url = "https://$master_server:$NB_PORT/netbackup/eventlog/notifications"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = common::send_http_request($url, "POST", $token, $payload, undef, $CONTENT_TYPE_V4); + + if (defined $json) { + print "Successfully completed POST Notifications.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: POST Notifications Request Failed!\n"; + } +} + +1; diff --git a/snippets/perl/eventlogs/get_notifications.pl b/snippets/perl/eventlogs/get_notifications.pl new file mode 100644 index 0000000..0cc39a6 --- /dev/null +++ b/snippets/perl/eventlogs/get_notifications.pl @@ -0,0 +1,74 @@ +#Load module netbackup.pm +use lib"../."; + +use netbackup; +use strict; +use eventlogs::eventlogs; +use warnings; +use Getopt::Long qw(GetOptions); + +sub printUsage { + print "\nUsage : perl get_notifications.pl -nbmaster -username -password [-domainname ] [-domaintype ] [-filter ] [--verbose]\n\n"; + die; +} + +my $fqdn_hostname; +my $username; +my $password; +my $domainname; +my $domaintype; +my $filter; +my $verbose; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'username=s' => \$username, +'password=s' => \$password, +'domainname=s' => \$domainname, +'domaintype=s' => \$domaintype, +'filter=s' => \$filter, +'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$username || !$password) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Username : $username\n"; + print " Password : $password\n"; + if ($domainname) { + print " Domain Name : $domainname\n"; + } + if ($domaintype) { + print " Domain Type : $domaintype\n"; + } + if ($filter) { + print " Filter : $filter\n"; + } +} + +print "\n"; +my $myToken; +my $jsonstring; + +if ($domainname && $domaintype) { + $myToken = netbackup::login($fqdn_hostname, $username, $password, $domainname, $domaintype); +} else { + $myToken = netbackup::login($fqdn_hostname, $username, $password); +} + +if ($filter) { + $jsonstring = eventlogs::getNotificationsByFilter($fqdn_hostname, $myToken, $filter); +} else { + $jsonstring = eventlogs::getNotificationsByFilter($fqdn_hostname, $myToken); +} + + +print "\nNotifications:\n"; +eventlogs::displayNotifications($jsonstring); + +netbackup::logout($fqdn_hostname, $myToken); +print "\n"; diff --git a/snippets/perl/eventlogs/post_notifications.pl b/snippets/perl/eventlogs/post_notifications.pl new file mode 100644 index 0000000..d94d410 --- /dev/null +++ b/snippets/perl/eventlogs/post_notifications.pl @@ -0,0 +1,64 @@ +#Load module netbackup.pm +use lib"../."; + +use netbackup; +use gateway; +use eventlogs::eventlogs; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl post_notifications.pl -nbmaster -username -password -payload [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $payload; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'username=s' => \$username, +'password=s' => \$password, +'domainname=s' => \$domainname, +'domaintype=s' => \$domaintype, +'payload=s' => \$payload, +'verbose' => \$verbose +) or printUsage(); + + +if (!$fqdn_hostname || !$username || !$password || !$payload) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Username : $username\n"; + print " Password : $password\n"; + if ($domainname) { + print " Domain Name : $domainname\n"; + } + if ($domaintype) { + print " Domain Type : $domaintype\n"; + } + if ($filter) { + print " Filter : $filter\n"; + } +} + +print "\n"; +my $myToken; +my $jsonstring; + +if ($domainname && $domaintype) { + $myToken = netbackup::login($fqdn_hostname, $username, $password, $domainname, $domaintype); +} else { + $myToken = netbackup::login($fqdn_hostname, $username, $password); +} + +my $jsonString = eventlogs::postNotifications($fqdn_hostname, $myToken, $payload); +print "$jsonString\n"; + +gateway::perform_logout($fqdn_hostname, $myToken); diff --git a/snippets/perl/get_all_resource_limits.pl b/snippets/perl/get_all_resource_limits.pl new file mode 100644 index 0000000..6708161 --- /dev/null +++ b/snippets/perl/get_all_resource_limits.pl @@ -0,0 +1,62 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use netbackup; +use strict; +use warnings; +use Getopt::Long qw(GetOptions); + +sub printUsage { + print "\nUsage : perl get_all_resource_limits.pl -nbmaster -username -password [-domainname ] [-domaintype ] [--verbose]\n\n"; + die; +} + +my $fqdn_hostname; +my $username; +my $password; +my $domainname; +my $domaintype; +my $verbose; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'username=s' => \$username, +'password=s' => \$password, +'domainname=s' => \$domainname, +'domaintype=s' => \$domaintype, +'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$username || !$password) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Username : $username\n"; + print " Password : $password\n"; + if ($domainname) { + print " Domain Name : $domainname\n"; + } + if ($domaintype) { + print " Domain Type : $domaintype\n"; + } +} + +print "\n"; +my $myToken; +if ($domainname && $domaintype) { + $myToken = netbackup::login($fqdn_hostname, $username, $password, $domainname, $domaintype); +} +else{ + $myToken = netbackup::login($fqdn_hostname, $username, $password); +} + +my $jsonstring = netbackup::getAllResourceLimits($fqdn_hostname, $myToken); + +print "\nNetBackup resource limits for all supported workload types:\n"; +netbackup::displayAllResourceLimits($jsonstring); + +netbackup::logout($fqdn_hostname, $myToken); +print "\n"; diff --git a/snippets/perl/get_all_resource_limits_templates.pl b/snippets/perl/get_all_resource_limits_templates.pl new file mode 100644 index 0000000..9798358 --- /dev/null +++ b/snippets/perl/get_all_resource_limits_templates.pl @@ -0,0 +1,62 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use netbackup; +use strict; +use warnings; +use Getopt::Long qw(GetOptions); + +sub printUsage { + print "\nUsage : perl get_all_resource_limits_templates.pl -nbmaster -username -password [-domainname ] [-domaintype ] [--verbose]\n\n"; + die; +} + +my $fqdn_hostname; +my $username; +my $password; +my $domainname; +my $domaintype; +my $verbose; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'username=s' => \$username, +'password=s' => \$password, +'domainname=s' => \$domainname, +'domaintype=s' => \$domaintype, +'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$username || !$password) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Username : $username\n"; + print " Password : $password\n"; + if ($domainname) { + print " Domain Name : $domainname\n"; + } + if ($domaintype) { + print " Domain Type : $domaintype\n"; + } +} + +print "\n"; +my $myToken; +if ($domainname && $domaintype) { + $myToken = netbackup::login($fqdn_hostname, $username, $password, $domainname, $domaintype); +} +else{ + $myToken = netbackup::login($fqdn_hostname, $username, $password); +} + +my $jsonstring = netbackup::getAllResourceLimitsTemplates($fqdn_hostname, $myToken); + +print "\nNetBackup resource limits templates for all supported workload types::\n"; +netbackup::displayAllResourceLimitsTemplates($jsonstring); + +netbackup::logout($fqdn_hostname, $myToken); +print "\n"; diff --git a/snippets/perl/get_resource_limits.pl b/snippets/perl/get_resource_limits.pl new file mode 100644 index 0000000..a78695c --- /dev/null +++ b/snippets/perl/get_resource_limits.pl @@ -0,0 +1,65 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use netbackup; +use strict; +use warnings; +use Getopt::Long qw(GetOptions); + +sub printUsage { + print "\nUsage : perl get_resource_limits.pl -nbmaster -username -password -workloadtype [-domainname ] [-domaintype ] [--verbose]\n\n"; + die; +} + +my $fqdn_hostname; +my $username; +my $password; +my $workloadtype; +my $domainname; +my $domaintype; +my $verbose; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'username=s' => \$username, +'password=s' => \$password, +'workloadtype=s' => \$workloadtype, +'domainname=s' => \$domainname, +'domaintype=s' => \$domaintype, +'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$username || !$password || !$workloadtype) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Username : $username\n"; + print " Password : $password\n"; + print " Workload Type : $workloadtype\n"; + if ($domainname) { + print " Domain Name : $domainname\n"; + } + if ($domaintype) { + print " Domain Type : $domaintype\n"; + } +} + +print "\n"; +my $myToken; +if ($domainname && $domaintype) { + $myToken = netbackup::login($fqdn_hostname, $username, $password, $domainname, $domaintype); +} +else{ + $myToken = netbackup::login($fqdn_hostname, $username, $password); +} + +my $jsonstring = netbackup::getResourceLimits($fqdn_hostname, $myToken, $workloadtype); + +print "\n Resource limits for a given workload type:\n"; +netbackup::displayResourceLimits($jsonstring); + +netbackup::logout($fqdn_hostname, $myToken); +print "\n"; diff --git a/snippets/perl/get_resource_limits_template.pl b/snippets/perl/get_resource_limits_template.pl new file mode 100644 index 0000000..b8c5b1c --- /dev/null +++ b/snippets/perl/get_resource_limits_template.pl @@ -0,0 +1,65 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use netbackup; +use strict; +use warnings; +use Getopt::Long qw(GetOptions); + +sub printUsage { + print "\nUsage : perl get_resource_limits_template.pl -nbmaster -username -password -workloadtype [-domainname ] [-domaintype ] [--verbose]\n\n"; + die; +} + +my $fqdn_hostname; +my $username; +my $password; +my $workloadtype; +my $domainname; +my $domaintype; +my $verbose; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'username=s' => \$username, +'password=s' => \$password, +'workloadtype=s' => \$workloadtype, +'domainname=s' => \$domainname, +'domaintype=s' => \$domaintype, +'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$username || !$password || !$workloadtype) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Username : $username\n"; + print " Password : $password\n"; + print " Workload Type : $workloadtype\n"; + if ($domainname) { + print " Domain Name : $domainname\n"; + } + if ($domaintype) { + print " Domain Type : $domaintype\n"; + } +} + +print "\n"; +my $myToken; +if ($domainname && $domaintype) { + $myToken = netbackup::login($fqdn_hostname, $username, $password, $domainname, $domaintype); +} +else{ + $myToken = netbackup::login($fqdn_hostname, $username, $password); +} + +my $jsonstring = netbackup::getResourceLimitsTemplate($fqdn_hostname, $myToken, $workloadtype); + +print "\n Resource limits template for a given workload type:\n"; +netbackup::displayResourceLimitsTemplate($jsonstring); + +netbackup::logout($fqdn_hostname, $myToken); +print "\n"; diff --git a/snippets/perl/get_vm_server.pl b/snippets/perl/get_vm_server.pl new file mode 100644 index 0000000..38625d6 --- /dev/null +++ b/snippets/perl/get_vm_server.pl @@ -0,0 +1,65 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use netbackup; +use strict; +use warnings; +use Getopt::Long qw(GetOptions); + +sub printUsage { + print "\nUsage : perl get_vm_server.pl -nbmaster -username -password -servername [-domainname ] [-domaintype ] [--verbose]\n\n"; + die; +} + +my $fqdn_hostname; +my $username; +my $password; +my $servername; +my $domainname; +my $domaintype; +my $verbose; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'username=s' => \$username, +'password=s' => \$password, +'servername=s' => \$servername, +'domainname=s' => \$domainname, +'domaintype=s' => \$domaintype, +'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$username || !$password || !$servername) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Username : $username\n"; + print " Password : $password\n"; + print " Servername : $servername\n"; + if ($domainname) { + print " Domain Name : $domainname\n"; + } + if ($domaintype) { + print " Domain Type : $domaintype\n"; + } +} + +print "\n"; +my $myToken; +if ($domainname && $domaintype) { + $myToken = netbackup::login($fqdn_hostname, $username, $password, $domainname, $domaintype); +} +else{ + $myToken = netbackup::login($fqdn_hostname, $username, $password); +} + +my $jsonstring = netbackup::getVM_Server($fqdn_hostname, $myToken, $servername); + +print "\nVM Server:\n"; +netbackup::displayVM_Server($jsonstring); + +netbackup::logout($fqdn_hostname, $myToken); +print "\n"; diff --git a/snippets/perl/get_vm_servers.pl b/snippets/perl/get_vm_servers.pl new file mode 100644 index 0000000..402a0ba --- /dev/null +++ b/snippets/perl/get_vm_servers.pl @@ -0,0 +1,62 @@ +#Load module netbackup.pm from current directory +use lib '.'; + +use netbackup; +use strict; +use warnings; +use Getopt::Long qw(GetOptions); + +sub printUsage { + print "\nUsage : perl get_vm_servers.pl -nbmaster -username -password [-domainname ] [-domaintype ] [--verbose]\n\n"; + die; +} + +my $fqdn_hostname; +my $username; +my $password; +my $domainname; +my $domaintype; +my $verbose; + +GetOptions( +'nbmaster=s' => \$fqdn_hostname, +'username=s' => \$username, +'password=s' => \$password, +'domainname=s' => \$domainname, +'domaintype=s' => \$domaintype, +'verbose' => \$verbose +) or printUsage(); + +if (!$fqdn_hostname || !$username || !$password) { + printUsage(); +} + +if($verbose){ + print "\nRecieved the following parameters : \n"; + print " FQDN Hostname : $fqdn_hostname\n"; + print " Username : $username\n"; + print " Password : $password\n"; + if ($domainname) { + print " Domain Name : $domainname\n"; + } + if ($domaintype) { + print " Domain Type : $domaintype\n"; + } +} + +print "\n"; +my $myToken; +if ($domainname && $domaintype) { + $myToken = netbackup::login($fqdn_hostname, $username, $password, $domainname, $domaintype); +} +else{ + $myToken = netbackup::login($fqdn_hostname, $username, $password); +} + +my $jsonstring = netbackup::getVM_Servers($fqdn_hostname, $myToken); + +print "\nVM servers:\n"; +netbackup::displayVM_Servers($jsonstring); + +netbackup::logout($fqdn_hostname, $myToken); +print "\n"; diff --git a/snippets/perl/netbackup.pm b/snippets/perl/netbackup.pm index e1cf730..ce0b47a 100644 --- a/snippets/perl/netbackup.pm +++ b/snippets/perl/netbackup.pm @@ -11,6 +11,8 @@ use LWP::Protocol::https; $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0; $CONTENT_TYPE_V1 = "application/vnd.netbackup+json; version=1.0"; $CONTENT_TYPE_V2 = "application/vnd.netbackup+json; version=2.0"; +$CONTENT_TYPE_V3 = "application/vnd.netbackup+json; version=3.0"; +$HYPERV = "Hyper-V"; $NB_PORT = 1556; @@ -204,6 +206,272 @@ sub getCatalogImages { } +# +# This function returns requested VM server. +# +sub getVM_Server { + + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to getVM_Server()\n"; + print "Usage : getVM_Server( , , ) \n"; + return; + } + + my $fqdn_hostname = $_[0]; + my $token = $_[1]; + my $servername = $_[2]; + + my $url = "https://$fqdn_hostname:$NB_PORT/netbackup/config/servers/vmservers/"; + $url .= $servername; + my $vmserver_req = HTTP::Request->new(GET => $url); + $vmserver_req->header('Authorization' => $token); + $vmserver_req->header('content-type' => "$CONTENT_TYPE_V2"); + + my $ua = LWP::UserAgent->new( + timeout => 500, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "Performing GET VM server request on $url\n"; + my $response = $ua->request($vmserver_req); + if ($response->is_success) { + print "Successfully completed GET VM server request.\n"; + + $data = decode_json($response->content); + my $pretty = JSON->new->pretty->encode($data); + return $pretty; + } + else { + print "ERROR :: Get VM server request Failed!\n"; + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + #die; let this fall through to cleanup code + } + +} + +# +# This function returns a list of VM servers +# +sub getVM_Servers { + + my $arguments_count = scalar(@_); + if ($arguments_count != 2) { + print "ERROR :: Incorrect number of arguments passed to getVM_Servers()\n"; + print "Usage : getVM_Servers( , ) \n"; + return; + } + + my $fqdn_hostname = $_[0]; + my $token = $_[1]; + + my $url = "https://$fqdn_hostname:$NB_PORT/netbackup/config/servers/vmservers/"; + my $vmservers_req = HTTP::Request->new(GET => $url); + $vmservers_req->header('Authorization' => $token); + $vmservers_req->header('content-type' => "$CONTENT_TYPE_V2"); + + my $ua = LWP::UserAgent->new( + timeout => 500, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "Performing GET VM servers request on $url\n"; + my $response = $ua->request($vmservers_req); + if ($response->is_success) { + print "Successfully completed GET VM servers request.\n"; + + $data = decode_json($response->content); + my $pretty = JSON->new->pretty->encode($data); + return $pretty; + } + else { + print "ERROR :: GET VM servers request Failed!\n"; + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + #die; let this fall through to cleanup code + } + +} + + +# +# This function returns a list of all NetBackup resource limits +# +sub getAllResourceLimits { + + my $arguments_count = scalar(@_); + if ($arguments_count != 2) { + print "ERROR :: Incorrect number of arguments passed to getAllResourceLimits()\n"; + print "Usage : getAllResourceLimits( , ) \n"; + return; + } + + my $fqdn_hostname = $_[0]; + my $token = $_[1]; + + my $url = "https://$fqdn_hostname:$NB_PORT/netbackup/config/resource-limits"; + my $allResourceLimits_req = HTTP::Request->new(GET => $url); + $allResourceLimits_req->header('Authorization' => $token); + $allResourceLimits_req->header('content-type' => "$CONTENT_TYPE_V3"); + + my $ua = LWP::UserAgent->new( + timeout => 500, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "Performing GET all NetBackup resource limits request on $url\n"; + my $response = $ua->request($allResourceLimits_req); + if ($response->is_success) { + print "Successfully completed GET all NetBackup resource limits request.\n"; + + $data = decode_json($response->content); + my $pretty = JSON->new->pretty->encode($data); + return $pretty; + } + else { + print "ERROR :: GET all NetBackup resource limits request Failed!\n"; + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + #die; let this fall through to cleanup code + } + +} + +# +# This function returns a list of resource limits for a given workload type. +# +sub getResourceLimits { + + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to getResourceLimits()\n"; + print "Usage : getResourceLimits( , , ) \n"; + return; + } + + my $fqdn_hostname = $_[0]; + my $token = $_[1]; + my $workloadtype = $_[2]; + + my $url = "https://$fqdn_hostname:$NB_PORT/netbackup/config/resource-limits/"; + $url .= $workloadtype; + my $resourceLimits_req = HTTP::Request->new(GET => $url); + $resourceLimits_req->header('Authorization' => $token); + $resourceLimits_req->header('content-type' => "$CONTENT_TYPE_V3"); + + my $ua = LWP::UserAgent->new( + timeout => 500, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "Performing GET resource limits for a given workload type request on $url\n"; + my $response = $ua->request($resourceLimits_req); + if ($response->is_success) { + print "Successfully completed GET resource limits for a given workload type.\n"; + + $data = decode_json($response->content); + my $pretty = JSON->new->pretty->encode($data); + return $pretty; + } + else { + print "ERROR :: GET resource limits for a given workload type request Failed!\n"; + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + #die; let this fall through to cleanup code + } + +} + +# +# This function returns a list of all NetBackup resource limits templates. +# +sub getAllResourceLimitsTemplates { + + my $arguments_count = scalar(@_); + if ($arguments_count != 2) { + print "ERROR :: Incorrect number of arguments passed to getAllResourceLimitsTemplates()\n"; + print "Usage : getAllResourceLimitsTemplates( , ) \n"; + return; + } + + my $fqdn_hostname = $_[0]; + my $token = $_[1]; + + my $url = "https://$fqdn_hostname:$NB_PORT/netbackup/config/resource-limit-templates"; + my $allResourceLimitsTemplates_req = HTTP::Request->new(GET => $url); + $allResourceLimitsTemplates_req->header('Authorization' => $token); + $allResourceLimitsTemplates_req->header('content-type' => "$CONTENT_TYPE_V3"); + + my $ua = LWP::UserAgent->new( + timeout => 500, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "Performing Get all resource limits templates request on $url\n"; + my $response = $ua->request($allResourceLimitsTemplates_req); + if ($response->is_success) { + print "Successfully completed Get all resource limits templates request.\n"; + + $data = decode_json($response->content); + my $pretty = JSON->new->pretty->encode($data); + return $pretty; + } + else { + print "ERROR :: Get all resource limits templates Failed!\n"; + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + #die; let this fall through to cleanup code + } + +} + +# +# This function returns NetBackup resource limits template for a given workload type. +# +sub getResourceLimitsTemplate { + + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to getResourceLimitsTemplate()\n"; + print "Usage : getResourceLimitsTemplate( , , ) \n"; + return; + } + + my $fqdn_hostname = $_[0]; + my $token = $_[1]; + my $workloadtype = $_[2]; + + my $url = "https://$fqdn_hostname:$NB_PORT/netbackup/config/resource-limit-templates/"; + $url .= $workloadtype; + my $resourceLimitsTemplate_req = HTTP::Request->new(GET => $url); + $resourceLimitsTemplate_req->header('Authorization' => $token); + $resourceLimitsTemplate_req->header('content-type' => "$CONTENT_TYPE_V3"); + + my $ua = LWP::UserAgent->new( + timeout => 500, + ssl_opts => { verify_hostname => 0, SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE }, + ); + + print "Performing GET resource limits template for a given workload type request on $url\n"; + my $response = $ua->request($resourceLimitsTemplate_req); + if ($response->is_success) { + print "Successfully completed GET resource limits template for a given workload type request.\n"; + + $data = decode_json($response->content); + my $pretty = JSON->new->pretty->encode($data); + return $pretty; + } + else { + print "ERROR :: GET resource limits template for a given workload type Failed!\n"; + print "HTTP GET error code: ", $response->code, "\n"; + print "HTTP GET error message: ", $response->message, "\n"; + #die; let this fall through to cleanup code + } + +} + + # # This function displays data in a tabular form. It takes table title array and # table data (2-d matrix) as inputs and renders it in a tabular form with border @@ -317,6 +585,241 @@ sub displayCatalogImages { } +# +# This function displays the Json content returned from VM Servers API +# in a tabular format +# +sub displayVM_Servers { + + my $arguments_count = scalar(@_); + if ($arguments_count != 1) { + print "ERROR :: Incorrect number of arguments passed to displayVM_Servers()\n"; + print "Usage : displayVM_Servers( ) \n"; + return; + } + + my $jsonstring = $_[0]; + my $json = decode_json($jsonstring); + my @vm_servers = @{$json->{'data'}}; + + my @tablerows; + + foreach (@vm_servers) { + my $vm_server = $_; + + my $serverName = $vm_server->{'attributes'}->{'vmServer'}->{'serverName'}; + my $vmType = $vm_server->{'attributes'}->{'vmServer'}->{'vmType'}; + my $userId = $vm_server->{'attributes'}->{'vmServer'}->{'userId'}; + my $port = $vm_server->{'attributes'}->{'vmServer'}->{'port'}; + + my @tablerow = ($serverName, $vmType, $userId, $port); + push @tablerows, \@tablerow; + } + + my @title = ("Server Name", "VM Type", "User ID", "Port"); + print "\n"; + displayDataInTable(\@title, \@tablerows); + print "\n"; + +} + +# +# This function displays the Json content returned from VM Server API +# in a tabular format +# +sub displayVM_Server { + + my $arguments_count = scalar(@_); + if ($arguments_count != 1) { + print "ERROR :: Incorrect number of arguments passed to displayVM_Servers()\n"; + print "Usage : displayVM_Servers( ) \n"; + return; + } + + my $jsonstring = $_[0]; + my $json = decode_json($jsonstring); + + my $serverName = $json->{'vmServer'}->{'serverName'}; + my $vmType = $json->{'vmServer'}->{'vmType'}; + my $userId = $json->{'vmServer'}->{'userId'}; + my $port = $json->{'vmServer'}->{'port'}; + + my @tablerow = ($serverName, $vmType, $userId, $port); + push @tablerows, \@tablerow; + + my @title = ("Server Name", "VM Type", "User ID", "Port"); + print "\n"; + displayDataInTable(\@title, \@tablerows); + print "\n"; + +} + + +# +# This function displays the Json content returned from GET all resource limits API +# in a tabular format +# +sub displayAllResourceLimits { + + my $arguments_count = scalar(@_); + if ($arguments_count != 1) { + print "ERROR :: Incorrect number of arguments passed to displayAllResourceLimits()\n"; + print "Usage : displayAllResourceLimits( ) \n"; + return; + } + + my $jsonstring = $_[0]; + my $json = decode_json($jsonstring); + my @allResourceLimits = @{$json->{'data'}}; + + my @tablerows; + + foreach (@allResourceLimits) { + my $allResourceLimitsElement = $_; + my @resourceLimits = @{$allResourceLimitsElement->{'attributes'}->{'resources'}}; + my $workloadType = $allResourceLimitsElement->{'attributes'}->{'workloadType'}; + + foreach(@resourceLimits) { + my $resourceLimit = $_; + + my $resourceType = $resourceLimit->{'resourceType'}; + my $resourceName = $resourceLimit->{'resourceName'}; + my $resourceLimitValue = $resourceLimit->{'resourceLimit'}; + my @tablerow = ($workloadType, $resourceType, $resourceName, $resourceLimitValue); + push @tablerows, \@tablerow; + } + } + + my @title = ("Workload Type", "Resource Type", "Resource Name", "Resource Limit"); + print "\n"; + displayDataInTable(\@title, \@tablerows); + print "\n"; + +} + +# +# This function displays the Json content returned from GET resource limits for a given workload type API. +# in a tabular format +# +sub displayResourceLimits { + + my $arguments_count = scalar(@_); + if ($arguments_count != 1) { + print "ERROR :: Incorrect number of arguments passed to displayResourceLimits()\n"; + print "Usage : displayResourceLimits( ) \n"; + return; + } + + my $jsonstring = $_[0]; + my $json = decode_json($jsonstring); + my @resourceLimits = @{$json->{'data'}->{'attributes'}->{'resources'}}; + my $workloadType = $json->{'data'}->{'attributes'}->{'workloadType'}; + + foreach(@resourceLimits) { + my $resourceLimit = $_; + + my $resourceType = $resourceLimit->{'resourceType'}; + my $resourceName = $resourceLimit->{'resourceName'}; + my $resourceLimitValue = $resourceLimit->{'resourceLimit'}; + my @tablerow = ($workloadType, $resourceType, $resourceName, $resourceLimitValue); + push @tablerows, \@tablerow; + } + + my @title = ("Workload Type", "Resource Type", "Resource Name", "Resource Limit"); + print "\n"; + displayDataInTable(\@title, \@tablerows); + print "\n"; + +} + +# +# This function displays the Json content returned from GET all resource limits templates API +# in a tabular format +# +sub displayAllResourceLimitsTemplates { + + my $arguments_count = scalar(@_); + if ($arguments_count != 1) { + print "ERROR :: Incorrect number of arguments passed to displayAllResourceLimitsTemplates()\n"; + print "Usage : displayAllResourceLimitsTemplates( ) \n"; + return; + } + + my $jsonstring = $_[0]; + my $json = decode_json($jsonstring); + my @allResourceLimits = @{$json->{'data'}}; + + my @tablerows; + + foreach (@allResourceLimits) { + my $allResourceLimitsElement = $_; + my @resourceLimits = @{$allResourceLimitsElement->{'attributes'}->{'resources'}}; + my $workloadType = $allResourceLimitsElement->{'attributes'}->{'workloadType'}; + + foreach(@resourceLimits) { + my $resourceLimit = $_; + + my $resourceType = $resourceLimit->{'resourceType'}; + my $resourceDescription = $resourceLimit->{'resourceDescription'}; + $resourceDescription = join('',split(/\n/,$resourceDescription)); + my $backupMethod = ""; + if($workloadType eq $HYPERV) { + $backupMethod = $resourceLimit->{'backupMethod'}; + } + + my @tablerow = ($workloadType, $resourceType, $backupMethod, $resourceDescription); + push @tablerows, \@tablerow; + } + } + + my @title = ("Workload Type", "Resource Type", "Backup Method", "Resource Description"); + print "\n"; + displayDataInTable(\@title, \@tablerows); + print "\n"; + +} + + +# +# This function displays the Json content returned from GET resource limits template for a given workload type API. +# in a tabular format +# +sub displayResourceLimitsTemplate { + + my $arguments_count = scalar(@_); + if ($arguments_count != 1) { + print "ERROR :: Incorrect number of arguments passed to displayResourceLimitsTemplate()\n"; + print "Usage : displayResourceLimitsTemplate( ) \n"; + return; + } + + my $jsonstring = $_[0]; + my $json = decode_json($jsonstring); + my @resourceLimits = @{$json->{'data'}->{'attributes'}->{'resources'}}; + my $workloadType = $json->{'data'}->{'attributes'}->{'workloadType'}; + + foreach(@resourceLimits) { + my $resourceLimit = $_; + + my $resourceType = $resourceLimit->{'resourceType'}; + my $resourceDescription = $resourceLimit->{'resourceDescription'}; + $resourceDescription = join('',split(/\n/,$resourceDescription)); + my $backupMethod = ""; + if($workloadType eq $HYPERV) { + $backupMethod = $resourceLimit->{'backupMethod'}; + } + + my @tablerow = ($workloadType, $resourceType, $backupMethod, $resourceDescription); + push @tablerows, \@tablerow; + } + + my @title = ("Workload Type", "Resource Type", "Backup Method", "Resource Description"); + print "\n"; + displayDataInTable(\@title, \@tablerows); + print "\n"; + +} + # # This function returns a list of Asset based on # a filter parameter @@ -403,7 +906,7 @@ sub displayAssets { # ## This function create the Json payload for the Asset Cleanup API -## It receives 2 paramters, the Json response from the GetAssetByFilter +## It receives 2 parameters, the Json response from the GetAssetByFilter ## and the cleanupTime. The response of this function is a proper payload ## with all Assets from the filter. ## diff --git a/snippets/perl/storage/README.md b/snippets/perl/storage/README.md new file mode 100644 index 0000000..d217d30 --- /dev/null +++ b/snippets/perl/storage/README.md @@ -0,0 +1,80 @@ +### NetBackup API Code Samples for Perl + +This directory contains code samples to invoke NetBackup REST APIs using Perl. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher is required for configuring storage API +- Perl v5.18.2 +- Perl modules Text::Table, JSON and LWP + +#### Executing the snippets in Perl + +#### NOTE - Sample payloads from the snippets\sample-payloads\storage-samples location can be used as input to run the scripts. + +Create Storage Server: + +Use the following command to create the storage server on NetBackup Master server: + - perl post_storage_server.pl -nbmaster -username -password -payload [-domainname ] [-domaintype ] + +Update Storage Server: + +Use the following command to create the storage server on NetBackup Master server: + - perl patch_storage_server.pl -nbmaster -username -password -payload -stsid [-domainname ] [-domaintype ] + +Get Storage Server: + +Use the following command to create the storage server on NetBackup Master server: + - perl get_storage_server.pl -nbmaster -username -password -payload [-domainname ] [-domaintype ] + +Delete Storage Server: + +Use the following command to create the storage server on NetBackup Master server: + - perl delete_storage_server.pl -nbmaster -username -password -stsid [-domainname ] [-domaintype ] + +Create Storage unit: + +Use the following command to create the storage unit on NetBackup Master server: + - perl post_storage_unit.pl -nbmaster -username -password -payload [-domainname ] [-domaintype ] + +Update Storage unit: + +Use the following command to create the storage unit on NetBackup Master server: + - perl patch_storage_unit.pl -nbmaster -username -password -payload -stuname [-domainname ] [-domaintype ] + +Get Storage unit: + +Use the following command to create the storage unit on NetBackup Master server: + - perl get_storage_unit.pl -nbmaster -username -password [-domainname ] [-domaintype ] + +Delete Storage Unit: + +Use the following command to create the storage unit on NetBackup Master server: + - perl delete_storage_unit.pl -nbmaster -username -password -stu_name [-domainname ] [-domaintype ] + + +Create Disk Pool: + +Use the following command to create the disk pool on NetBackup Master server: + - perl post_disk_pool.pl -nbmaster -username -password -payload -dpid [-domainname ] [-domaintype ] + +Update Disk pool: + +Use the following command to create the disk pool on NetBackup Master server: + - perl patch_disk_pool.pl -nbmaster -username -password -payload -dpid [-domainname ] [-domaintype ] + +Get Disk Pool: + +Use the following command to create the disk pool on NetBackup Master server: + - perl get_disk_pool.pl -nbmaster -username -password [-domainname ] [-domaintype ] + +Delete Disk Pool: + +Use the following command to create the disk pool on NetBackup Master server: + - perl delete_storage_unit.pl -nbmaster -username -password -dpid [-domainname ] [-domaintype ] + + diff --git a/snippets/perl/storage/delete_disk_pool.pl b/snippets/perl/storage/delete_disk_pool.pl new file mode 100644 index 0000000..f1217d1 --- /dev/null +++ b/snippets/perl/storage/delete_disk_pool.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl delete_disk_pool.pl -nbmaster -username -password -dpid [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $dpid; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'dpid=s' => \$dpid, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::delete_disk_pool($master_server, $token, $dpid); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/delete_storage_server.pl b/snippets/perl/storage/delete_storage_server.pl new file mode 100644 index 0000000..9467332 --- /dev/null +++ b/snippets/perl/storage/delete_storage_server.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl delete_storage_server.pl -nbmaster -username -password -stsid [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $stsid; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'stsid=s' => \$stsid, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::delete_storage_server($master_server, $token, $stsid); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/delete_storage_unit.pl b/snippets/perl/storage/delete_storage_unit.pl new file mode 100644 index 0000000..48e8a46 --- /dev/null +++ b/snippets/perl/storage/delete_storage_unit.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl delete_storage_unit.pl -nbmaster -username -password -stu_name [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $stu_name; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'stu_name=s' => \$stu_name, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::delete_storage_unit($master_server, $token, $stu_name); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/get_disk_pool.pl b/snippets/perl/storage/get_disk_pool.pl new file mode 100644 index 0000000..c262eaf --- /dev/null +++ b/snippets/perl/storage/get_disk_pool.pl @@ -0,0 +1,35 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl get_disk_pool.pl -nbmaster -username -password [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::get_disk_pool($master_server, $token); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/get_disk_pool_by_id.pl b/snippets/perl/storage/get_disk_pool_by_id.pl new file mode 100644 index 0000000..1f4a1a3 --- /dev/null +++ b/snippets/perl/storage/get_disk_pool_by_id.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl get_disk_pool_by_id.pl -nbmaster -username -password -dpid [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $dpid; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'dpid=s' => \$dpid, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::get_disk_pool_by_id($master_server, $token, $dpid); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/get_storage_server.pl b/snippets/perl/storage/get_storage_server.pl new file mode 100644 index 0000000..077c563 --- /dev/null +++ b/snippets/perl/storage/get_storage_server.pl @@ -0,0 +1,35 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl get_storage_server.pl -nbmaster -username -password -payload [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::get_storage_server($master_server, $token); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/get_storage_server_by_id.pl b/snippets/perl/storage/get_storage_server_by_id.pl new file mode 100644 index 0000000..a13d983 --- /dev/null +++ b/snippets/perl/storage/get_storage_server_by_id.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl get_storage_server_by_id.pl -nbmaster -username -password -stsid [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $stsid; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'stsid=s' => \$stsid, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::get_storage_server_by_id($master_server, $token, $stsid); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/get_storage_unit.pl b/snippets/perl/storage/get_storage_unit.pl new file mode 100644 index 0000000..4c272dc --- /dev/null +++ b/snippets/perl/storage/get_storage_unit.pl @@ -0,0 +1,35 @@ +#Load module netbackup.pm from current directory + +use lib"../."; +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl get_storage_unit.pl -nbmaster -username -password [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::get_storage_unit($master_server, $token); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/get_storage_unit_by_id.pl b/snippets/perl/storage/get_storage_unit_by_id.pl new file mode 100644 index 0000000..744a8c9 --- /dev/null +++ b/snippets/perl/storage/get_storage_unit_by_id.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl get_storage_unit_by_id.pl -nbmaster -username -password -stu_name [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $stu_name; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'stu_name=s' => \$stu_name, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::get_storage_unit_by_name($master_server, $token, $stu_name); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/patch_disk_pool.pl b/snippets/perl/storage/patch_disk_pool.pl new file mode 100644 index 0000000..008c678 --- /dev/null +++ b/snippets/perl/storage/patch_disk_pool.pl @@ -0,0 +1,39 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl patch_disk_pool.pl -nbmaster -username -password -payload -dpid [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $payload_file; +my $dpid; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'payload=s' => \$payload_file, +'dpid=s' => \$dpid, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::patch_disk_pool($master_server, $token, $payload_file, $dpid); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/patch_storage_server.pl b/snippets/perl/storage/patch_storage_server.pl new file mode 100644 index 0000000..fc8b102 --- /dev/null +++ b/snippets/perl/storage/patch_storage_server.pl @@ -0,0 +1,39 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl patch_storage_server.pl -nbmaster -username -password -payload -stsid [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $payload_file; +my $stsid; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'payload=s' => \$payload_file, +'stsid=s' => \$stsid, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::patch_storage_server($master_server, $token, $payload_file, $stsid); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/patch_storage_unit.pl b/snippets/perl/storage/patch_storage_unit.pl new file mode 100644 index 0000000..87f6dbb --- /dev/null +++ b/snippets/perl/storage/patch_storage_unit.pl @@ -0,0 +1,39 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl patch_storage_unit.pl -nbmaster -username -password -payload -stu_name [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $payload_file; +my $stu_name; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'payload=s' => \$payload_file, +'stu_name=s' => \$stu_name, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::patch_storage_unit($master_server, $token, $payload_file, $stu_name); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); \ No newline at end of file diff --git a/snippets/perl/storage/post_disk_pool.pl b/snippets/perl/storage/post_disk_pool.pl new file mode 100644 index 0000000..d4136f2 --- /dev/null +++ b/snippets/perl/storage/post_disk_pool.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl post_disk_pool.pl -nbmaster -username -password -payload -dpid [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $payload_file; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'payload=s' => \$payload_file, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::post_disk_pool($master_server, $token, $payload_file); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/post_storage_server.pl b/snippets/perl/storage/post_storage_server.pl new file mode 100644 index 0000000..25c787e --- /dev/null +++ b/snippets/perl/storage/post_storage_server.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl post_storage_server.pl -nbmaster -username -password -payload [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $payload_file; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'payload=s' => \$payload_file, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::post_storage_server($master_server, $token, $payload_file); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/post_storage_unit.pl b/snippets/perl/storage/post_storage_unit.pl new file mode 100644 index 0000000..a7c8496 --- /dev/null +++ b/snippets/perl/storage/post_storage_unit.pl @@ -0,0 +1,37 @@ +#Load module netbackup.pm from current directory +use lib"../."; + +use gateway; +use storage::storage; +use Getopt::Long qw(GetOptions); +sub printUsage { + print "\nUsage : perl post_storage_unit.pl -nbmaster -username -password -payload [-domainname ] [-domaintype ]\n\n"; + die; +} + +my $master_server; +my $username; +my $password; +my $payload_file; +my $domainname; +my $domaintype; + +GetOptions( +'nbmaster=s' => \$master_server, +'username=s' => \$username, +'password=s' => \$password, +'payload=s' => \$payload_file, +'domainname=s' => \$domain_name, +'domaintype=s' => \$domain_type, +) or printUsage(); + +if (!$master_server || !$username || !$password) { + printUsage(); +} + +my $token = gateway::perform_login($master_server, $username, $password, $domain_name, $domain_type); + +my $jsonString = storage::post_storage_unit($master_server, $token, $payload_file); +print "$jsonString\n"; + +gateway::perform_logout($master_server, $token); diff --git a/snippets/perl/storage/storage.pm b/snippets/perl/storage/storage.pm new file mode 100644 index 0000000..44b7fd7 --- /dev/null +++ b/snippets/perl/storage/storage.pm @@ -0,0 +1,468 @@ +#!/usr/bin/env perl + +package storage; + +use common; +use JSON; +use warnings; +use LWP::UserAgent; +use LWP::Protocol::https; + +$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0; +$CONTENT_TYPE = "application/vnd.netbackup+json;version=3.0"; +$PROTOCOL = "https://"; +$NB_PORT = 1556; + +# Create a storage server +sub post_storage_server { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to post_storage_server()\n"; + print "Usage : post_storage_server( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-servers"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = common::send_http_request($url, "POST", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed POST Storage Server Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: POST Storage Server Request Failed!\n"; + } +} + +# Update storage server +sub patch_storage_server { + my $arguments_count = scalar(@_); + if ($arguments_count != 4) { + print "ERROR :: Incorrect number of arguments passed to patch_storage_server()\n"; + print "Usage : patch_storage_server( , , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $stsid = $_[3]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-servers/$stsid"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = common::send_http_request($url, "PATCH", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed PATCH Storage Server Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: PATCH Storage Server Request Failed!\n"; + } +} + +# Create a storage unit +sub post_storage_unit { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to post_storage_unit()\n"; + print "Usage : post_storage_unit( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-units"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = common::send_http_request($url, "POST", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed POST Storage Unit Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: POST Storage Unit Request Failed!\n"; + } +} + +# Create a storage unit +sub post_disk_pool { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to post_disk_pool()\n"; + print "Usage : post_disk_pool( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/disk-pools"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = common::send_http_request($url, "POST", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed POST Disk Pool Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: POST Disk Pool Request Failed!\n"; + } +} + +# get storage unit +sub get_storage_unit { + my $arguments_count = scalar(@_); + if ($arguments_count != 2) { + print "ERROR :: Incorrect number of arguments passed to get_storage_unit()\n"; + print "Usage : get_storage_unit( , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-units"; + + my $json = common::send_http_request($url, "GET", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed GET Storage Unit Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: GET Storage Unit Request Failed!\n"; + } +} + +# Update disk pool +sub patch_disk_pool { + my $arguments_count = scalar(@_); + if ($arguments_count != 4) { + print "ERROR :: Incorrect number of arguments passed to patch_disk_pool()\n"; + print "Usage : patch_disk_pool( , , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $filename = $_[2]; + my $dpid = $_[3]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/disk-pools/$dpid"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = common::send_http_request($url, "PATCH", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed PATCH Disk Pool Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: PATCH Disk Pool Request Failed!\n"; + } +} + +# get Disk Pool +sub get_disk_pool { + my $arguments_count = scalar(@_); + if ($arguments_count != 2) { + print "ERROR :: Incorrect number of arguments passed to get_disk_pool()\n"; + print "Usage : get_disk_pool( , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/disk-pools"; + + my $json = common::send_http_request($url, "GET", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed GET DiskPool Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: GET DiskPool Request Failed!\n"; + } +} + +# update storage unit +sub patch_storage_unit { + my $arguments_count = scalar(@_); + if ($arguments_count != 4) { + print "ERROR :: Incorrect number of arguments passed to patch_storage_unit()\n"; + print "Usage : patch_storage_unit( , , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $stu_name = $_[3]; + my $token = $_[1]; + my $filename = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-units/$stu_name"; + open(my $fh, '<:encoding(UTF-8)', $filename) + or die "Could not open file '$filename' $!"; + + my $payload = ""; + while (my $row = <$fh>) { + chomp $row; + $payload .= $row; + } + print "payload: $payload\n"; + + my $json = common::send_http_request($url, "PATCH", $token, $payload, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed PATCH Storage unit Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: PATCH Storage unit Request Failed!\n"; + } +} + +# get storage server +sub get_storage_server { + my $arguments_count = scalar(@_); + if ($arguments_count != 2) { + print "ERROR :: Incorrect number of arguments passed to get_storage_server()\n"; + print "Usage : get_storage_server( , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-servers"; + + my $json = common::send_http_request($url, "GET", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed GET Storage Server Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: GET Storage Server Request Failed!\n"; + } +} + +# get storage server +sub delete_storage_server { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to delete_storage_server()\n"; + print "Usage : delete_storage_server( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $stsid = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-servers/$stsid"; + + my $json = common::send_http_request($url, "DELETE", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed DELETE Storage Server Request.\n"; + + } + else { + print "ERROR :: DELETE Storage Server Request Failed!\n"; + } +} + +# delete disk pool +sub delete_disk_pool { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to delete_disk_pool()\n"; + print "Usage : delete_disk_pool( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $dpid = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/disk-pools/$dpid"; + + my $json = common::send_http_request($url, "DELETE", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed DELETE Disk Pool Request.\n"; + } + else { + print "ERROR :: DELETE Disk pool Request Failed!\n"; + } +} + +# delete disk pool +sub delete_storage_unit { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to delete_storage_unit()\n"; + print "Usage : delete_storage_unit( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $stu_name = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-units/$stu_name"; + + my $json = common::send_http_request($url, "DELETE", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed DELETE Storage unit Request.\n"; + } + else { + print "ERROR :: DELETE Storage unit Request Failed!\n"; + } +} + +# get storage server +sub get_storage_server_by_id { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to get_storage_server_by_id()\n"; + print "Usage : get_storage_server_by_id( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $stsid = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-servers/$stsid"; + + my $json = common::send_http_request($url, "GET", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed GET Storage Server Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + + } + else { + print "ERROR :: GET Storage Server by ID Failed!\n"; + } +} + +# delete disk pool +sub get_disk_pool_by_id { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to get_disk_pool_by_id()\n"; + print "Usage : get_disk_pool_by_id( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $dpid = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/disk-pools/$dpid"; + + my $json = common::send_http_request($url, "GET", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed GET Disk Pool Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: GET Disk Pool by ID Request Failed!\n"; + } +} + +# delete disk pool +sub get_storage_unit_by_name { + my $arguments_count = scalar(@_); + if ($arguments_count != 3) { + print "ERROR :: Incorrect number of arguments passed to get_storage_unit_by_name()\n"; + print "Usage : get_storage_unit_by_name( , , ) \n"; + return; + } + + my $master_server = $_[0]; + my $token = $_[1]; + my $stu_name = $_[2]; + my $url = "$PROTOCOL$master_server:$NB_PORT/netbackup/storage/storage-units/$stu_name"; + + my $json = common::send_http_request($url, "GET", $token, undef, undef, $CONTENT_TYPE); + + if (defined $json) { + print "Successfully completed GET Storage Unit Request.\n"; + + my $pretty = JSON->new->pretty->encode($json); + return $pretty; + } + else { + print "ERROR :: GET Storage unit by Name Request Failed!\n"; + } +} +1; + diff --git a/snippets/powershell/APIKey-Create.ps1 b/snippets/powershell/APIKey-Create.ps1 new file mode 100644 index 0000000..60c591a --- /dev/null +++ b/snippets/powershell/APIKey-Create.ps1 @@ -0,0 +1,161 @@ +<# + +.SYNOPSIS +This script demonstrates how to create API key for a user (self/others). To +create API key for other user, a user needs to have proper permissions. + +.DESCRIPTION +This script will create API Key for a user. + + +.EXAMPLE +./APIKey-Create.ps1 -nbmaster -login_username -login_password -login_domainname -login_domaintype [-apikey_username [-apikey_domainname ] -apikey_domaintype ] -expiryindays -description +-nbmaster : Name of the NetBackup master server +-login_username : User name of the user performing action +-login_password : Password of the user performing action +-login_domainname : Domain name of the user performing action +-login_domaintype : Domain type of the user performing action +-apikey_username : (Optional) User name of the user for whom API key needs to be generated. Optional in case API key is to be generated for self +-apikey_domainname : Domain name of the user for whom API key needs to be generated. Optional in case API key is to be generated for self. Blank in case -apikey_domaintype parameter is 'unixpwd' +-apikey_domaintype : Domain type of the user for whom API key needs to be generated. Optional in case API key is to be generated for self +-expiryindays : Number of days from today after which API key should expire +-description : A textual description to be associated with API key + +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$login_username = $(throw "Please specify the user name using -login_username parameter."), + [string]$login_password = $(throw "Please specify the password using -login_password parameter."), + [string]$login_domainname = $(throw "Please specify the domain name using -login_domain_name parameter."), + [string]$login_domaintype = $(throw "Please specify the domain type using -login_domaintype parameter."), + [string]$expiryindays = $(throw "Please specify the expiry period in days using -expiryindays parameter."), + [string]$description = $(throw "Please specify the description using -description parameter."), + [string]$apikey_username, + [string]$apikey_domainname, + [string]$apikey_domaintype +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type = "application/vnd.netbackup+json;version=1.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$login_username + password=$login_password + domainName=$login_domainname + domainType=$login_domaintype +} +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} + +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# Create API key +##################################################################### + +$uri = $basepath + "/security/api-keys" +$content_type = "application/vnd.netbackup+json;version=3.0" + +$headers = @{ + "Authorization" = $content.token +} + +# Construct request body +if ($apikey_username -ne "" -and $apikey_domaintype -ne "") +{ + $request_body = @{ + data = @{ + type = 'apiKeyCreationRequest' + attributes = @{ + description = $description + expireAfterDays = "P" + $expiryindays + "D" + userName = $apikey_username + userDomain = $apikey_domainname + userDomainType = $apikey_domaintype + } + } + } + +} +else { + $request_body = @{ + data = @{ + type = 'apiKeyCreationRequest' + attributes = @{ + description = $description + expireAfterDays = "P" + $expiryindays + "D" + } + } + } +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $request_body) ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 201) +{ + throw "Unable to create API key!" +} + +$response | ConvertTo-Json | ConvertFrom-Json diff --git a/snippets/powershell/APIKey-Delete.ps1 b/snippets/powershell/APIKey-Delete.ps1 new file mode 100644 index 0000000..33aecda --- /dev/null +++ b/snippets/powershell/APIKey-Delete.ps1 @@ -0,0 +1,123 @@ +<# + +.SYNOPSIS +This script demonstrates how to delete API key for a user (self/others). To +delete API key for other user, a user needs to have proper permissions. + +.DESCRIPTION +This script will delete API Key for a user. + + +.EXAMPLE +./APIKey-Delete.ps1 -nbmaster -login_username -login_password -login_domainname -login_domaintype -apikey_tag +-nbmaster : Name of the NetBackup master server +-login_username : User name of the user performing action +-login_password : Password of the user performing action +-login_domainname : Domain name of the user performing action +-login_domaintype : Domain type of the user performing action +-apikey_tag : Tag associate with API key to be deleted + +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$login_username = $(throw "Please specify the user name using -login_username parameter."), + [string]$login_password = $(throw "Please specify the password using -login_password parameter."), + [string]$login_domainname = $(throw "Please specify the domain name using -login_domain_name parameter."), + [string]$login_domaintype = $(throw "Please specify the domain type using -login_domaintype parameter."), + [string]$apikey_tag = $(throw "Please specify the apikey tag using -apikey_tag parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type = "application/vnd.netbackup+json;version=1.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$login_username + password=$login_password + domainName=$login_domainname + domainType=$login_domaintype +} +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} + +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# Delete API key +##################################################################### + +$uri = $basepath + "/security/api-keys/" + $apikey_tag +$content_type = "application/vnd.netbackup+json;version=3.0" + +$headers = @{ + "Authorization" = $content.token +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method DELETE ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 204) +{ + throw "Unable to delete API key!" +} + +$response | ConvertTo-Json | ConvertFrom-Json diff --git a/snippets/powershell/APIKey-Usage.ps1 b/snippets/powershell/APIKey-Usage.ps1 new file mode 100644 index 0000000..9d6f3b8 --- /dev/null +++ b/snippets/powershell/APIKey-Usage.ps1 @@ -0,0 +1,107 @@ +<# + +.SYNOPSIS +This script demonstrates the usage of API key in netbackup REST API for listing the jobs + +.DESCRIPTION +This script will get a list of netbackup jobs and print the details of the last 10 jobs in a tabular format. +The REST API triggered uses API key in 'Authorization' header instead of using JWT. This avoids the step of +acquiring JWT after login to NetBackup. + + +.EXAMPLE +./APIKey-Usage.ps1 -nbmaster "nb-master.example.com" -apikey "apikey" +-nbmaster : Name of the NetBackup master server +-apikey : API key to be used instead of JWT + +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$apikey = $(throw "Please specify the api key using -apikey parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Get NetBackup Jobs +##################################################################### + +$uri = $basepath + "/admin/jobs" + +$headers = @{ + "Authorization" = $apikey +} + +$query_params = @{ +# "page[limit]" = 100 # This changes the default page size to 100 +# "filter" = "jobType eq 'RESTORE'" # This adds a filter to only show the restore jobs +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -Body $query_params ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 200) +{ + throw "Unable to get the Netbackup jobs!" +} + +$content = (ConvertFrom-Json -InputObject $response) + +# This prints all the available attributes +#$content.data.attributes | Format-Table -AutoSize + +$properties = + @{Label = "Job ID"; Expression = { $_.attributes.jobId }}, + @{Label = "Type"; Expression = { $_.attributes.jobType }}, + @{Label = "State"; Expression = { $_.attributes.state }}, + @{Label = "Status"; Expression = { $_.attributes.status }} + +$content.data | Format-Table -AutoSize -Property $properties diff --git a/snippets/powershell/Get-NB-Alerts.ps1 b/snippets/powershell/Get-NB-Alerts.ps1 index 419b52f..3dc128d 100644 --- a/snippets/powershell/Get-NB-Alerts.ps1 +++ b/snippets/powershell/Get-NB-Alerts.ps1 @@ -43,8 +43,8 @@ function InitialSetup() # Force TLS v1.2 try { - if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { - [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 + if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) } } catch { diff --git a/snippets/powershell/Get-NB-Images.ps1 b/snippets/powershell/Get-NB-Images.ps1 index 02ea380..beab104 100644 --- a/snippets/powershell/Get-NB-Images.ps1 +++ b/snippets/powershell/Get-NB-Images.ps1 @@ -43,8 +43,8 @@ function InitialSetup() # Force TLS v1.2 try { - if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { - [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 + if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) } } catch { @@ -125,4 +125,4 @@ $properties = @{Label = "Client"; Expression = { $_.attributes.clientName }}, @{Label = "Backup Time"; Expression = { $_.attributes.backupTime }} -$content.data | Format-Table -AutoSize -Property $properties \ No newline at end of file +$content.data | Format-Table -AutoSize -Property $properties diff --git a/snippets/powershell/Get-NB-Jobs.ps1 b/snippets/powershell/Get-NB-Jobs.ps1 index 87480a7..26bf67a 100644 --- a/snippets/powershell/Get-NB-Jobs.ps1 +++ b/snippets/powershell/Get-NB-Jobs.ps1 @@ -43,8 +43,8 @@ function InitialSetup() # Force TLS v1.2 try { - if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { - [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 + if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) } } catch { diff --git a/snippets/powershell/Get-NB-PolicyDetails.ps1 b/snippets/powershell/Get-NB-PolicyDetails.ps1 new file mode 100644 index 0000000..8a433c6 --- /dev/null +++ b/snippets/powershell/Get-NB-PolicyDetails.ps1 @@ -0,0 +1,124 @@ +<# +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for listing the jobs. +.DESCRIPTION +This script will get a list of netbackup jobs and print the details of the last 10 jobs in a tabular format. +.EXAMPLE +./Get-NB-PolicyDetails.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -nbpolicy "policy_name" +#> + +param ( + + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$nbpolicy = $(throw "Please specify the policy using -nbpolicy parameter.") + + ) + + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type = "application/vnd.netbackup+json;version=2.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} + +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# Get the detais for a named policy... +##################################################################### + +$uri = $basepath + "/config/policies/" + $nbpolicy + +$headers = @{ + "Authorization" = $content.token + "X-NetBackup-Policy-Use-Generic-Schema" = $true +} + +$query_params = @{} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -Body $query_params ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 200) +{ + throw "Unable to get the policy details for $nbpolicy!" +} + +$content = (ConvertFrom-Json -InputObject $response) + + +# This prints the majority of policies attributes... +$content.data.attributes.policy.policyAttributes + +# This prints the policy client list... +#$content.data.attributes.policy.clients.hostname + +# This prints the backup selections... +#$content.data.attributes.policy.backupSelections.selections diff --git a/snippets/powershell/Get-NB-ReissueToken.ps1 b/snippets/powershell/Get-NB-ReissueToken.ps1 new file mode 100644 index 0000000..7411596 --- /dev/null +++ b/snippets/powershell/Get-NB-ReissueToken.ps1 @@ -0,0 +1,151 @@ +<# +.SYNOPSIS +This sample script demonstrates how to use NetBackup API to generate a new reissue token. +.DESCRIPTION +This script will generate a new reissue token for the host specified in -nbclient. +.EXAMPLE +./Get-NB-ReissueToken.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -nbclient "nb-client.example.com" +#> + +param ( + + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$nbclient = $(throw "Please specify the client using -nbclient parameter.") + + ) + + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + + # Add TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type = "application/vnd.netbackup+json;version=2.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} + +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# Get the host UUID for a hostname... +##################################################################### + +$uri = $basepath + "/config/hosts" + +$headers = @{ + "Authorization" = $content.token +} + +$query_params = @{"name"=$nbclient} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method GET ` + -Body $query_params ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 200) +{ + throw "Unable to get the UUID for client $nbclient!" +} + +$myToken = $content.token + +$content = (ConvertFrom-Json -InputObject $response) + +# capture the uuid... +$uuid = $content.uuid + +##################################################################### +# Get Reissue token +##################################################################### + +$uri = $basepath + "/security/securitytokens" + +$headers = @{ + "Authorization" = $myToken +} + +$body = @{ + allowedCount=1 + hostId=$uuid + tokenName=$nbclient + "_reissue" + type=1 + validFor=86400 +} +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type ` + -Headers $headers + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} + +$content = (ConvertFrom-Json -InputObject $response) + +$content diff --git a/snippets/powershell/Post-NB-Cleanup-Assets.ps1 b/snippets/powershell/Post-NB-Cleanup-Assets.ps1 index c683929..e54cc86 100644 --- a/snippets/powershell/Post-NB-Cleanup-Assets.ps1 +++ b/snippets/powershell/Post-NB-Cleanup-Assets.ps1 @@ -52,8 +52,8 @@ function InitialSetup() # Force TLS v1.2 try { - if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { - [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 + if ([Net.ServicePointManager]::SecurityProtocol -notmatch 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) } } catch { @@ -169,4 +169,4 @@ if (!$content_get.data){ { throw "Unable to delete Assets " + $assetIds } -} \ No newline at end of file +} diff --git a/snippets/powershell/README.md b/snippets/powershell/README.md index e6ceebe..5735929 100644 --- a/snippets/powershell/README.md +++ b/snippets/powershell/README.md @@ -9,6 +9,7 @@ These scripts are only meant to be used as a reference. If you intend to use the #### Pre-requisites: - NetBackup 8.1.1 or higher +- NetBackup 8.2 or higher for using API keys related APIs and samples - PowerShell 5.0 or higher #### Executing the snippets in PowerShell @@ -16,4 +17,20 @@ These scripts are only meant to be used as a reference. If you intend to use the Use the following commands to run the PowerShell samples. - `.\Get-NB-Images.ps1 -nbmaster -username -password ` - `.\Get-NB-Jobs.ps1 -nbmaster -username -password ` +- `.\Get-NB-PolicyDetails.ps1 -nbmaster -username -password -nbpolicy ` +- `.\Get-NB-ReissueToken.ps1 -nbmaster -username -password -nbclient ` - `.\Post-NB-Cleanup-Assets.ps1 -nbmaster -username -password -filter -cleanupTime 2018-06-29T15:18:45.678Z` + +#### Scripts for NetBackup 8.2 or higher + +Use the following command to create an API key for yourself on your NetBackup Master server: + - `.\apikey_create.ps1 -nbmaster -login_username -login_password -login_domainname -login_domaintype -expiryindays -description ` + +Use the following command to create an API key for other user on your NetBackup Master server: + - `.\apikey_create.ps1 -nbmaster -login_username -login_password -login_domainname -login_domaintype -apikey_username [-apikey_domainname ] -apikey_domaintype -expiryindays -description ` + +- Use the following command to delete an API key on your NetBackup Master server with apikey tag provided: + - `.\apikey_delete.sh -nbmaster -login_username -login_password -login_domainname -login_domaintype -apikey_tag ` + +Use the following command to use API key instead of JWT to trigger a NetBackup REST API on your NetBackup Master server: + - `.\APIKey-Usage.ps1 -nbmaster -apikey ` diff --git a/snippets/powershell/storage/Delete-NB-delete-disk-pool.ps1 b/snippets/powershell/storage/Delete-NB-delete-disk-pool.ps1 new file mode 100644 index 0000000..d0652ca --- /dev/null +++ b/snippets/powershell/storage/Delete-NB-delete-disk-pool.ps1 @@ -0,0 +1,120 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for deleting scpecified disk pool. + +.DESCRIPTION +This script will delete scpecified disk pool. + +.EXAMPLE +./Delete-NB-delete-disk-pool.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -dpid "disk pool id" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$dpid = $(throw "Please specify the dpid using -dpid parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# Delete NetBackup Disk Pool +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/disk-pools/" + $dpid + + +$response_delete = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + +if ($response_delete.StatusCode -ne 204 ) +{ + throw "Unable to delete disk pool." +} + +Write-Host "Disk pool deleted successfully.`n" +Write-Host $response_delete + +$response_delete = (ConvertFrom-Json -InputObject $response_delete) diff --git a/snippets/powershell/storage/Delete-NB-delete-storage-server.ps1 b/snippets/powershell/storage/Delete-NB-delete-storage-server.ps1 new file mode 100644 index 0000000..98c70ba --- /dev/null +++ b/snippets/powershell/storage/Delete-NB-delete-storage-server.ps1 @@ -0,0 +1,120 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for deleting scpecified storage server. + +.DESCRIPTION +This script will delete scpecified storage server. + +.EXAMPLE +./Delete-NB-delete-storage-server.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -stsid "storage server id" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$stsid = $(throw "Please specify the stsid using -stsid parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# Delete NetBackup Storage servers +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers/" + $stsid + + +$response_delete = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + +if ($response_delete.StatusCode -ne 204) +{ + throw "Unable to delete storage server." +} + +Write-Host "storage server deleted successfully.`n" +Write-Host $response_delete + +$response_delete = (ConvertFrom-Json -InputObject $response_delete) diff --git a/snippets/powershell/storage/Delete-NB-delete-storage-unit.ps1 b/snippets/powershell/storage/Delete-NB-delete-storage-unit.ps1 new file mode 100644 index 0000000..7184952 --- /dev/null +++ b/snippets/powershell/storage/Delete-NB-delete-storage-unit.ps1 @@ -0,0 +1,120 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for deleting scpecified storage unit. + +.DESCRIPTION +This script will delete scpecified storage unit. + +.EXAMPLE +./Delete-NB-delete-storage-unit.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -stu_name "storage unit name" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$stu_name = $(throw "Please specify the stu_name using -stu_name parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# Delete NetBackup storage units +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$stu_uri = $basepath + "/storage/storage-units/" + $stu_name + + +$response_delete = Invoke-WebRequest ` + -Uri $stu_uri ` + -Method DELETE ` + -ContentType $contentType ` + -Headers $headers + +if ($response_delete.StatusCode -ne 204) +{ + throw "Unable to delete storage unit." +} + +Write-Host "storage unit deleted successfully.`n" +Write-Host $response_delete + +$response_delete = (ConvertFrom-Json -InputObject $response_delete) diff --git a/snippets/powershell/storage/Get-NB-get-disk-pool-by-id.ps1 b/snippets/powershell/storage/Get-NB-get-disk-pool-by-id.ps1 new file mode 100644 index 0000000..baada1d --- /dev/null +++ b/snippets/powershell/storage/Get-NB-get-disk-pool-by-id.ps1 @@ -0,0 +1,120 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for fetching scpecified disk pool. + +.DESCRIPTION +This script will fetch scpecified disk pool. + +.EXAMPLE +./Get-NB-get-disk-pool-by-id.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -dpid "disk pool id" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$dpid = $(throw "Please specify the dpid using -dpid parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# GET NetBackup Disk Pool +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/disk-pools/" + $dpid + + +$response_get = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + +if ($response_get.StatusCode -ne 200) +{ + throw "Unable to fetch disk pool." +} + +Write-Host "Disk pool fetched successfully.`n" +Write-Host $response_get + +$response_get = (ConvertFrom-Json -InputObject $response_get) diff --git a/snippets/powershell/storage/Get-NB-get-disk-pool.ps1 b/snippets/powershell/storage/Get-NB-get-disk-pool.ps1 new file mode 100644 index 0000000..4e770d8 --- /dev/null +++ b/snippets/powershell/storage/Get-NB-get-disk-pool.ps1 @@ -0,0 +1,119 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for fetching disk pools. + +.DESCRIPTION +This script will fetch disk pools. + +.EXAMPLE +./Get-NB-get-disk-pool.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# GET NetBackup Disk Pools +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/disk-pools" + + +$response_getAll = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + +if ($response_getAll.StatusCode -ne 200) +{ + throw "Unable to fetch disk pools." +} + +Write-Host "disk pools fetched successfully.`n" +Write-Host $response_getAll + +$response_getAll = (ConvertFrom-Json -InputObject $response_getAll) diff --git a/snippets/powershell/storage/Get-NB-get-storage-server-by-id.ps1 b/snippets/powershell/storage/Get-NB-get-storage-server-by-id.ps1 new file mode 100644 index 0000000..03076e7 --- /dev/null +++ b/snippets/powershell/storage/Get-NB-get-storage-server-by-id.ps1 @@ -0,0 +1,120 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for fetching scpecified storage server. + +.DESCRIPTION +This script will fetch scpecified storage server. + +.EXAMPLE +./Get-NB-get-storage-server-by-id.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -stsid "storage server id" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$stsid = $(throw "Please specify the stsid using -stsid parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# GET NetBackup Storage servers +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers/" + $stsid + + +$response_get = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + +if ($response_get.StatusCode -ne 200) +{ + throw "Unable to fetch storage server." +} + +Write-Host "storage server fetched successfully.`n" +Write-Host $response_get + +$response_get = (ConvertFrom-Json -InputObject $response_get) diff --git a/snippets/powershell/storage/Get-NB-get-storage-server.ps1 b/snippets/powershell/storage/Get-NB-get-storage-server.ps1 new file mode 100644 index 0000000..14ba47c --- /dev/null +++ b/snippets/powershell/storage/Get-NB-get-storage-server.ps1 @@ -0,0 +1,119 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for fetching storage servers. + +.DESCRIPTION +This script will fetch storage servers. + +.EXAMPLE +./Get-NB-get-storage-server.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# GET NetBackup Storage servers +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers" + + +$response_getAll = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + +if ($response_getAll.StatusCode -ne 200) +{ + throw "Unable to fetch storage servers." +} + +Write-Host "storage servers fetched successfully.`n" +Write-Host $response_getAll + +$response_getAll = (ConvertFrom-Json -InputObject $response_getAll) diff --git a/snippets/powershell/storage/Get-NB-get-storage-unit-by-id.ps1 b/snippets/powershell/storage/Get-NB-get-storage-unit-by-id.ps1 new file mode 100644 index 0000000..a43431e --- /dev/null +++ b/snippets/powershell/storage/Get-NB-get-storage-unit-by-id.ps1 @@ -0,0 +1,120 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for fetching scpecified storage unit. + +.DESCRIPTION +This script will fetch scpecified storage unit. + +.EXAMPLE +./Get-NB-get-storage-unit-by-id.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -stu_name "storage unit name" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$stu_name = $(throw "Please specify the stu_name using -stu_name parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# GET NetBackup storage unit +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-units/" + $stu_name + + +$response_get = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + +if ($response_get.StatusCode -ne 200) +{ + throw "Unable to fetch storage unit." +} + +Write-Host "storage unit fetched successfully.`n" +Write-Host $response_get + +$response_get = (ConvertFrom-Json -InputObject $response_get) diff --git a/snippets/powershell/storage/Get-NB-get-storage-unit.ps1 b/snippets/powershell/storage/Get-NB-get-storage-unit.ps1 new file mode 100644 index 0000000..7423f49 --- /dev/null +++ b/snippets/powershell/storage/Get-NB-get-storage-unit.ps1 @@ -0,0 +1,119 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for fetching storage units. + +.DESCRIPTION +This script will fetch storage units. + +.EXAMPLE +./Get-NB-get-storage-unit.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# GET NetBackup Storage Units +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-units" + + +$response_getAll = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method GET ` + -ContentType $contentType ` + -Headers $headers + +if ($response_getAll.StatusCode -ne 200) +{ + throw "Unable to fetch storage units." +} + +Write-Host "storage units fetched successfully.`n" +Write-Host $response_getAll + +$response_getAll = (ConvertFrom-Json -InputObject $response_getAll) diff --git a/snippets/powershell/storage/Patch-NB-update-ad-storage-server.ps1 b/snippets/powershell/storage/Patch-NB-update-ad-storage-server.ps1 new file mode 100644 index 0000000..4661442 --- /dev/null +++ b/snippets/powershell/storage/Patch-NB-update-ad-storage-server.ps1 @@ -0,0 +1,136 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for updating Advanced disk storage server. + +.DESCRIPTION +This script will update Advanced disk storage server. + +.EXAMPLE +./Patch-NB-update-ad-storage-server.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -stsid "storage server id" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$stsid = $(throw "Please specify the stsid using -stsid parameter.") + +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# PATCH NetBackup Storage server +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers/" + $stsid + +$json = '{ +"data": { + "type": "storageServer", + "attributes": { + "advancedDiskAttributes": { + "isPreferredForRestore": false, + "isRequiredForRestore": false, + "isRequiredForDuplication": false + } + + } + } +} +' +$response_update = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method PATCH ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_update.StatusCode -ne 200) +{ + throw "Unable to update storage server." +} + +Write-Host "storage server updated successfully.`n" +echo $response_update +Write-Host $response_update + +$response_update = (ConvertFrom-Json -InputObject $response_update) diff --git a/snippets/powershell/storage/Patch-NB-update-cloud-storage-server.ps1 b/snippets/powershell/storage/Patch-NB-update-cloud-storage-server.ps1 new file mode 100644 index 0000000..b827c51 --- /dev/null +++ b/snippets/powershell/storage/Patch-NB-update-cloud-storage-server.ps1 @@ -0,0 +1,144 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for updating cloud storage server. + +.DESCRIPTION +This script will update cloud storage server. + +.EXAMPLE +./Patch-NB-update-cloud-storage-server.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -stsid "storage server id" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$stsid = $(throw "Please specify the stsid using -stsid parameter.") + +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# PATCH NetBackup Storage server +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers/" + $stsid + +$json = '{ + "data": { + "type": "storageServer", + "attributes": { + "cloudAttributes": { + "readBufferSizeBytes": 419430401, + "writeBufferSizeBytes": 419430401, + "curlDetails": { + "curlLoggingEnabled": true, + "curlTimeOutSeconds": 1200, + "curlConnectionTimeOutSeconds": 600 + }, + "sslDetails": { + "useSSLMode": "NONE", + "checkCertificateRevocation": false + } + } + } + } +} +' + +$response_update = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method PATCH ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_update.StatusCode -ne 200) +{ + throw "Unable to update storage server." +} + +Write-Host "storage server updated successfully.`n" +echo $response_update +Write-Host $response_update + +$response_update = (ConvertFrom-Json -InputObject $response_update) diff --git a/snippets/powershell/storage/Patch-NB-update-disk-pool.ps1 b/snippets/powershell/storage/Patch-NB-update-disk-pool.ps1 new file mode 100644 index 0000000..9819ce3 --- /dev/null +++ b/snippets/powershell/storage/Patch-NB-update-disk-pool.ps1 @@ -0,0 +1,136 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for updating disk pool. + +.DESCRIPTION +This script will update disk pool. + +.EXAMPLE +./Patch-NB-update-disk-pool.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -dpid "disk pool id" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$dpid = $(throw "Please specify the dpid using -dpid parameter.") + +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# PATCH NetBackup disk pool +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/disk-pools/" + $dpid + +$json = '{ + "data": { + "type": "diskPool", + "attributes": { + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 100 + }, + "diskPoolState": "UP" + } + } +} +' + +$response_update = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method PATCH ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_update.StatusCode -ne 200) +{ + throw "Unable to update disk pool." +} + +Write-Host "disk pool updated successfully.`n" +echo $response_update +Write-Host $response_update + +$response_update = (ConvertFrom-Json -InputObject $response_update) diff --git a/snippets/powershell/storage/Patch-NB-update-msdp-storage-server.ps1 b/snippets/powershell/storage/Patch-NB-update-msdp-storage-server.ps1 new file mode 100644 index 0000000..f2ce4da --- /dev/null +++ b/snippets/powershell/storage/Patch-NB-update-msdp-storage-server.ps1 @@ -0,0 +1,135 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for updating msdp storage server. + +.DESCRIPTION +This script will update msdp storage server. + +.EXAMPLE +./Patch-NB-update-msdp-storage-server.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -stsid "storage server id" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$stsid = $(throw "Please specify the stsid using -stsid parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# PATCH NetBackup Storage server +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers/" + $stsid + +$json = '{ + "data": { + "type": "storageServer", + "attributes": { + "msdpAttributes": { + "credentials": { + "userName": "USER_NAME", + "password": "PASSWORD" + } + } + } + } +} +' +$response_update = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method PATCH ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_update.StatusCode -ne 200) +{ + throw "Unable to update storage server." +} + +Write-Host "storage server updated successfully.`n" +echo $response_update +Write-Host $response_update + +$response_update = (ConvertFrom-Json -InputObject $response_update) diff --git a/snippets/powershell/storage/Patch-NB-update-storage-unit.ps1 b/snippets/powershell/storage/Patch-NB-update-storage-unit.ps1 new file mode 100644 index 0000000..749e885 --- /dev/null +++ b/snippets/powershell/storage/Patch-NB-update-storage-unit.ps1 @@ -0,0 +1,134 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for updating storage unit. + +.DESCRIPTION +This script will update storage unit. + +.EXAMPLE +./Patch-NB-update-storage-unit.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" -stu_name "storage unit name" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter."), + [string]$stu_name = $(throw "Please specify the stu_name using -stu_name parameter.") + +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# PATCH NetBackup Storage Unit +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$stu_uri = $basepath + "/storage/storage-units/" + $stu_name + +$json = '{ + "data": { + "type": "storageUnit", + "attributes": { + "maxFragmentSizeMegabytes": 50100, + "maxConcurrentJobs": 8, + "onDemandOnly": true + } + } +} +' + +$response_update = Invoke-WebRequest ` + -Uri $stu_uri ` + -Method PATCH ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_update.StatusCode -ne 200) +{ + throw "Unable to update storage unit." +} + +Write-Host "storage units updated successfully.`n" +echo $response_update +Write-Host $response_update + +$response_update = (ConvertFrom-Json -InputObject $response_update) diff --git a/snippets/powershell/storage/Post-NB-create-ad-disk-pool.ps1 b/snippets/powershell/storage/Post-NB-create-ad-disk-pool.ps1 new file mode 100644 index 0000000..e680723 --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-ad-disk-pool.ps1 @@ -0,0 +1,151 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating disk pool for Advanced Disk storage server. + +.DESCRIPTION +This script will create disk pool for Advanced Disk storage server. + +.EXAMPLE +./Post-NB-create-ad-disk-pool.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Disk Pool +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$dp_uri = $basepath + "/storage/disk-pools" + +$json = '{ + "data": { + "type": "diskPool", + "attributes": { + "name": "disk-pool1", + "diskVolumes": [ + { + "name": "C:\\" + } + ], + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 4 + } + }, + "relationships": { + "storageServers": { + "data": [ + { + "type": "storageServer", + "id": "STORAGE_SERVER_ID" + } + ] + } + } + } +} +' +echo $json + +$response_create_dp = Invoke-WebRequest ` + -Uri $dp_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_dp.StatusCode -ne 201) +{ + Write-Host $response_create_dp + throw "Unable to create Disk Pool." +} + +Write-Host "Disk Pool created successfully.`n" +echo $response_create_dp +Write-Host $response_create_dp + +$response_create_dp = (ConvertFrom-Json -InputObject $response_create_dp) diff --git a/snippets/powershell/storage/Post-NB-create-ad-storage-server.ps1 b/snippets/powershell/storage/Post-NB-create-ad-storage-server.ps1 new file mode 100644 index 0000000..2f8dd1a --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-ad-storage-server.ps1 @@ -0,0 +1,139 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating Advanced disk storage server. + +.DESCRIPTION +This script will create Advanced disk storage server. + +.EXAMPLE +./Post-NB-create-ad-storage-server.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Storage server +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers" + +$json = '{ + "data": { + "type": "storageServer", + "attributes": { + "name": "STORAGE_SERVER_NAME", + "storageCategory": "ADVANCED_DISK", + "mediaServerDetails": { + "name": "MEDIA_SERVER" + }, + "advancedDiskAttributes": { + "isPreferredForRestore": true, + "isRequiredForRestore": true, + "isRequiredForDuplication": false + } + } + } +} +' + +$response_create_sts = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_sts.StatusCode -ne 201) +{ + throw "Unable to create storage server." +} + +Write-Host "storage server created successfully.`n" +echo $response_create_sts +Write-Host $response_create_sts + +$response_create_sts = (ConvertFrom-Json -InputObject $response_create_sts) diff --git a/snippets/powershell/storage/Post-NB-create-ad-storage-unit.ps1 b/snippets/powershell/storage/Post-NB-create-ad-storage-unit.ps1 new file mode 100644 index 0000000..3f103a5 --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-ad-storage-unit.ps1 @@ -0,0 +1,142 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating storage unit for Advanced disk storage server. + +.DESCRIPTION +This script will create storage unit for Advanced disk storage server. + +.EXAMPLE +./Post-NB-create-ad-storage-unit.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Storage unit +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-units" + +$json = '{ + "data": { + "type": "storageUnit", + "attributes": { + "name": "my-stu", + "useAnyAvailableMediaServer": true, + "maxFragmentSizeMegabytes": 51200, + "maxConcurrentJobs": 5, + "onDemandOnly": true + }, + "relationships": { + "diskPool": { + "data": { + "type": "diskPool", + "id": "DISK_POOL_ID" + } + } + } + } +} +' + +$response_create_stu = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_stu.StatusCode -ne 201) +{ + throw "Unable to create storage unit." +} + +Write-Host "storage unit created successfully.`n" +echo $response_create_stu +Write-Host $response_create_stu + +$response_create_stu = (ConvertFrom-Json -InputObject $response_create_stu) diff --git a/snippets/powershell/storage/Post-NB-create-cloud-disk-pool.ps1 b/snippets/powershell/storage/Post-NB-create-cloud-disk-pool.ps1 new file mode 100644 index 0000000..39e67ac --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-cloud-disk-pool.ps1 @@ -0,0 +1,150 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating disk pool for cloud storage server. + +.DESCRIPTION +This script will create disk pool for cloud storage server. + +.EXAMPLE +./Post-NB-create-cloud-disk-pool.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Disk Pool +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/disk-pools" + +$json = '{ + "data": { + "type": "diskPool", + "attributes": { + "name": "disk-pool1", + "diskVolumes": [ + { + "name": "BUCKET_NAME" + } + ], + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 4 + } + }, + "relationships": { + "storageServers": { + "data": [ + { + "type": "storageServer", + "id": "STORAGE_SERVER_ID" + } + ] + } + } + } +} + +' + +$response_create_dp = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_dp.StatusCode -ne 201) +{ + throw "Unable to create Disk Pool." +} + +Write-Host "Disk Pool created successfully.`n" +echo $response_create_dp +Write-Host $response_create_dp + +$response_create_dp = (ConvertFrom-Json -InputObject $response_create_dp) diff --git a/snippets/powershell/storage/Post-NB-create-cloud-storage-server.ps1 b/snippets/powershell/storage/Post-NB-create-cloud-storage-server.ps1 new file mode 100644 index 0000000..94f84cc --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-cloud-storage-server.ps1 @@ -0,0 +1,152 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating cloud storage server. + +.DESCRIPTION +This script will create cloud storage server. + +.EXAMPLE +./Post-NB-create-cloud-storage-server.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Storage server +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers" + +$json = '{ + "data": { + "type": "storageServer", + "attributes": { + "name": "amazonstss.com", + "storageCategory": "CLOUD", + "mediaServerDetails": { + "name": "MEDIA_SERVER" + }, + "cloudAttributes": { + "providerId": "amazon", + "compressionEnabled": true, + "s3RegionDetails": [ + { + "serviceHost": "SERVICE-HOST", + "regionName": "REGION_NAME", + "regionId": "REGION_ID" + } + ], + "cloudCredentials": { + "authType": "ACCESS_KEY", + "accessKeyDetails": { + "userName": "USER_ID", + "password": "PASSWORD" + } + } + } + } + } +} +' + +$response_create_sts = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_sts.StatusCode -ne 201) +{ + throw "Unable to create storage server." +} + +Write-Host "storage server created successfully.`n" +echo $response_create_sts +Write-Host $response_create_sts + +$response_create_sts = (ConvertFrom-Json -InputObject $response_create_sts) diff --git a/snippets/powershell/storage/Post-NB-create-cloud-storage-unit.ps1 b/snippets/powershell/storage/Post-NB-create-cloud-storage-unit.ps1 new file mode 100644 index 0000000..18e2179 --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-cloud-storage-unit.ps1 @@ -0,0 +1,142 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating storage unit for cloud storage server. + +.DESCRIPTION +This script will create storage unit for cloud storage server. + +.EXAMPLE +./Post-NB-create-cloud-storage-unit.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Storage unit +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-units" + +$json = '{ + "data": { + "type": "storageUnit", + "attributes": { + "name": "cloud-stu", + "useAnyAvailableMediaServer": true, + "maxFragmentSizeMegabytes": 50000, + "maxConcurrentJobs": 10, + "onDemandOnly": true + }, + "relationships": { + "diskPool": { + "data" : { + "type": "diskPool", + "id": "DISK_POOL_ID" + } + } + } +} +} +' + +$response_create_stu = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_stu.StatusCode -ne 201) +{ + throw "Unable to create storage unit." +} + +Write-Host "storage unit created successfully.`n" +echo $response_create_stu +Write-Host $response_create_stu + +$response_create_stu = (ConvertFrom-Json -InputObject $response_create_stu) diff --git a/snippets/powershell/storage/Post-NB-create-msdp-disk-pool.ps1 b/snippets/powershell/storage/Post-NB-create-msdp-disk-pool.ps1 new file mode 100644 index 0000000..3995de2 --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-msdp-disk-pool.ps1 @@ -0,0 +1,149 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating disk pool for msdp storage server. + +.DESCRIPTION +This script will create disk pool for msdp storage server. + +.EXAMPLE +./Post-NB-create-msdp-disk-pool.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Disk Pool +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/disk-pools" + +$json = '{ + "data": { + "type": "diskPool", + "attributes": { + "name": "msdp-dp1", + "diskVolumes": [ + { + "name":"PureDiskVolume" + } + ], + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 2 + } + }, + "relationships":{ + "storageServers": { + "data": [ + { + "type": "storageServer", + "id": "STORAGE_SERVER_ID" + } + ] + } + } + } + }' + + +$response_create_dp = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_dp.StatusCode -ne 201) +{ + throw "Unable to create Disk Pool." +} + +Write-Host "Disk Pool created successfully.`n" +echo $response_create_dp +Write-Host $response_create_dp + +$response_create_dp = (ConvertFrom-Json -InputObject $response_create_dp) diff --git a/snippets/powershell/storage/Post-NB-create-msdp-storage-server.ps1 b/snippets/powershell/storage/Post-NB-create-msdp-storage-server.ps1 new file mode 100644 index 0000000..de9da51 --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-msdp-storage-server.ps1 @@ -0,0 +1,143 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating storage unit for msdp. + +.DESCRIPTION +This script will create msdp storage server. + +.EXAMPLE +./Post-NB-create-msdp-storage-server.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Storage server +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-servers" + +$json = '{ +"data": { + "type": "storageServer", + "attributes": { + "name": "STORAGE_SERVER", + "storageCategory": "MSDP", + "mediaServerDetails": { + "name": "MEDIA_SERVER" + }, + "encryptionEnabled": true, + "msdpAttributes": { + "storagePath": "STORAGE_PATH", + "credentials": { + "userName": "MSDP_USERID", + "password": "MSDP_PASSWORD" + } + } + } + } + +} +' + +$response_create_sts = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_sts.StatusCode -ne 201) +{ + throw "Unable to create storage server." +} + +Write-Host "storage server created successfully.`n" +echo $response_create_sts +Write-Host $response_create_sts + +$response_create_sts = (ConvertFrom-Json -InputObject $response_create_sts) diff --git a/snippets/powershell/storage/Post-NB-create-msdp-storage-unit.ps1 b/snippets/powershell/storage/Post-NB-create-msdp-storage-unit.ps1 new file mode 100644 index 0000000..5e43574 --- /dev/null +++ b/snippets/powershell/storage/Post-NB-create-msdp-storage-unit.ps1 @@ -0,0 +1,143 @@ +<# + +.SYNOPSIS +This sample script demonstrates the use of NetBackup REST API for creating storage unit for msdp storage server. + +.DESCRIPTION +This script will create storage unit for msdp storage server. + +.EXAMPLE +./Post-NB-create-msdp-storage-unit.ps1 -nbmaster "nb-master.example.com" -username "administrator" -password "secret" +#> + +param ( + [string]$nbmaster = $(throw "Please specify the name of NetBackup master server using -nbmaster parameter."), + [string]$username = $(throw "Please specify the user name using -username parameter."), + [string]$password = $(throw "Please specify the password using -password parameter.") +) + +##################################################################### +# Initial Setup +# Note: This allows self-signed certificates and enables TLS v1.2 +##################################################################### + +function InitialSetup() +{ + + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Allow self-signed certificates + if ([System.Net.ServicePointManager]::CertificatePolicy -notlike 'TrustAllCertsPolicy') + { + Add-Type -TypeDefinition @" + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } +"@ + [System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy + [Net.ServicePointManager]::SecurityProtocol = "Tls12" + + # Force TLS v1.2 + try { + if ([Net.ServicePointManager]::SecurityProtocol -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12) + } + } + catch { + Write-Host $_.Exception.InnerException.Message + } + } +} + +InitialSetup + +##################################################################### +# Global Variables +##################################################################### + +$port = 1556 +$basepath = "https://" + $nbmaster + ":" + $port + "/netbackup" +$content_type1 = "application/vnd.netbackup+json;version=1.0" +$content_type2 = "application/vnd.netbackup+json;version=2.0" +$content_type3 = "application/vnd.netbackup+json;version=3.0" + +##################################################################### +# Login +##################################################################### + +$uri = $basepath + "/login" + +$body = @{ + userName=$username + password=$password +} + +$response = Invoke-WebRequest ` + -Uri $uri ` + -Method POST ` + -Body (ConvertTo-Json -InputObject $body) ` + -ContentType $content_type1 + +if ($response.StatusCode -ne 201) +{ + throw "Unable to connect to the Netbackup master server!" +} +Write-Host "Login successful.`n" +$content = (ConvertFrom-Json -InputObject $response) + +##################################################################### +# POST NetBackup Storage unit +##################################################################### + +$headers = @{ + "Authorization" = $content.token +} + +$sts_uri = $basepath + "/storage/storage-units" + +$json = '{ + "data": { + "type": "storageUnit", + "attributes": { + "name": "STORAGE_UNIT", + "useAnyAvailableMediaServer": true, + "maxFragmentSizeMegabytes": 50000, + "maxConcurrentJobs": 10, + "onDemandOnly": true + }, + "relationships": { + "diskPool": { + "data": { + "type": "diskPool", + "id": "DISK_POOL_ID" + } + } + } + } +} + +' + +$response_create_stu = Invoke-WebRequest ` + -Uri $sts_uri ` + -Method POST ` + -Body ($json) ` + -ContentType $content_type3 ` + -Headers $headers + +if ($response_create_stu.StatusCode -ne 201) +{ + throw "Unable to create storage unit." +} + +Write-Host "storage unit created successfully.`n" +echo $response_create_stu +Write-Host $response_create_stu + +$response_create_stu = (ConvertFrom-Json -InputObject $response_create_stu) diff --git a/snippets/powershell/storage/README.md b/snippets/powershell/storage/README.md new file mode 100644 index 0000000..4123fed --- /dev/null +++ b/snippets/powershell/storage/README.md @@ -0,0 +1,39 @@ +### NetBackup API Code Samples for PowerShell + +This directory contains code samples to invoke NetBackup REST APIs using PowerShell. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher +- PowerShell 5.0 or higher + +#### Executing the snippets in PowerShell + +Use the following commands to run the PowerShell samples. +- `.\Post-NB-create-msdp-storage-unit.ps1 -nbmaster -username -password ` +- `.\Post-NB-create-msdp-storage-server.ps1 -nbmaster -username -password ` +- `.\Post-NB-create-msdp-disk-pool.ps1 -nbmaster -username -password ` +- `.\Post-NB-create-cloud-storage-unit.ps1 -nbmaster -username -password ` +- `.\Post-NB-create-cloud-storage-server.ps1 -nbmaster -username -password ` +- `.\Post-NB-create-cloud-disk-pool.ps1 -nbmaster -username -password ` +- `.\Post-NB-create-ad-storage-unit.ps1 -nbmaster -username -password ` +- `.\Post-NB-create-ad-storage-server.ps1 -nbmaster -username -password ` +- `.\Post-NB-create-ad-disk-pool.ps1 -nbmaster -username -password ` +- `.\Get-NB-get-storage-server-by-id.ps1 -nbmaster -username -password -stsid ` +- `.\Get-NB-get-storage-server.ps1 -nbmaster -username -password ` +- `.\Get-NB-get-storage-unit.ps1 -nbmaster -username -password ` +- `.\Get-NB-get-disk-pool-by-id.ps1 -nbmaster -username -password -dpid ` +- `.\Get-NB-get-storage-unit-by-id.ps1 -nbmaster -username -password -stu_name ` +- `.\Get-NB-get-disk-pool.ps1 -nbmaster -username -password ` +- `.\Patch-NB-update-storage-unit.ps1 -nbmaster -username -password -stu_name ` +- `.\Patch-NB-update-msdp-storage-server.ps1 -nbmaster -username -password -stsid ` +- `.\Patch-NB-update-disk-pool.ps1 -nbmaster -username -password -dpid ` +- `.\Patch-NB-update-cloud-storage-server.ps1 -nbmaster -username -password -stsid ` +- `.\Patch-NB-update-ad-storage-server.ps1 -nbmaster -username -password -stsid ` +- `.\Delete-NB-delete-disk-pool.ps1 -nbmaster -username -password -dpid ` +- `.\Delete-NB-delete-storage-server.ps1 -nbmaster -username -password -stsid ` +- `.\Delete-NB-delete-storage-unit.ps1 -nbmaster -username -password -stu_name ` diff --git a/snippets/python/README.md b/snippets/python/README.md index b79628d..ef8b072 100644 --- a/snippets/python/README.md +++ b/snippets/python/README.md @@ -9,6 +9,7 @@ These scripts are only meant to be used as a reference. If you intend to use the #### Pre-requisites: - NetBackup 8.1.1 or higher +- NetBackup 8.2 or higher for using API keys related APIs and samples - python 3.5 or higher - python modules: `requests, texttable` @@ -17,3 +18,17 @@ These scripts are only meant to be used as a reference. If you intend to use the Use the following commands to run the python samples. - `python -W ignore get_nb_images.py -nbmaster -username -password [-domainname ] [-domaintype ]` - `python -W ignore get_nb_jobs.py -nbmaster -username -password [-domainname ] [-domaintype ]` + +#### Scripts for NetBackup 8.2 or higher + +- Use the following command to create an API key for yourself on your NetBackup Master server: + - `python -W apikey_create.py -nbmaster -login_username -login_password -login_domainname -login_domaintype -expiryindays -description ` + +- Use the following command to create an API key for other user on your NetBackup Master server: + - `python -W apikey_create.py -nbmaster -login_username -login_password -login_domainname -login_domaintype -apikey_username [-apikey_domainname ] -apikey_domaintype -expiryindays -description ` + +- Use the following command to delete an API key on your NetBackup Master server with apikey tag provided: + - `python -W apikey_delete.py -nbmaster -login_username -login_password -login_domainname -login_domaintype -apikey_tag ` + +Use the following command to use API key instead of JWT to trigger a NetBackup REST API on your NetBackup Master server: + - `python -W apikey_usage.py -nbmaster -apikey ` diff --git a/snippets/python/api_requests.py b/snippets/python/api_requests.py index 2b99899..5568b6e 100644 --- a/snippets/python/api_requests.py +++ b/snippets/python/api_requests.py @@ -1,6 +1,7 @@ import requests content_type = "application/vnd.netbackup+json; version=1.0" +content_type_v3 = "application/vnd.netbackup+json; version=3.0" def perform_login(username, password, base_url, domain_name, domain_type): url = base_url + "/login" @@ -73,3 +74,73 @@ def get_netbackup_alerts(jwt, base_url): raise Exception('Alert API failed with status code {} and {}'.format(resp.status_code, resp.json())) return resp.json() + +def get_netbackup_mssql_rps(jwt, base_url): + from datetime import datetime + my_date = datetime.now() + today = my_date.strftime('%Y-%m-%dT%H:%M:%SZ') + url = base_url + "/recovery-point-service/workloads/mssql/recovery-points/" + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + "page[limit]": 100, #This changes the default page size to 100 + "filter": "backupTime le '" + today + "' and backupType eq 1" # This filter will fetch FULL backups + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('Images API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +# Create NetBackup API key +# jwt - JWT fetched after triggering /login REST API +# base_usrl - NetBackup REST API base URL +# expiryindays - Number of days from today after which API key should expire +# description - A textual description to be associated with API key +# apikey_username - (optional) Username of the user whose API key needs to be generated. Empty string in case API keys is to be created for self. +# apikey_domainname - (optional) Domain name of the user whose API key needs to be generated. Empty string in case API keys is to be created for self or domain type is unixpwd. +# apikey_domaintype - (optional) Domain type of the user whose API key needs to be generated. Empty string in case API keys is to be created for self. +def apikey_create(jwt, base_url, expiryindays, description, apikey_username, apikey_domainname, apikey_domaintype): + url = base_url + "/security/api-keys" + + if apikey_username == "": + print("Creating API key for self user") + else: + print("Creating API key for user [" + apikey_username + ":" + apikey_domainname + ":" + apikey_domaintype + "]") + + if apikey_username != "" and apikey_domaintype != "": + req_body = { "data" : { "type":"apiKeyCreationRequest", "attributes": { "description":description, "expireAfterDays":"P" + expiryindays + "D", "userName":apikey_username, "userDomain":apikey_domainname, "userDomainType":apikey_domaintype} } } + else: + req_body = { "data" : { "type":"apiKeyCreationRequest", "attributes": { "description":description, "expireAfterDays":"P" + expiryindays + "D"} } } + + headers = {'Content-Type' :content_type_v3, 'Authorization': jwt} + + print("performing POST on {}\n".format(url)) + + resp = requests.post(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Create API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +# Delete NetBackup API key +# jwt - JWT fetched after triggering /login REST API +# base_usrl - NetBackup REST API base URL +# apikey_tag - Tag associated with API key +def apikey_delete(jwt, base_url, apikey_tag): + url = base_url + "/security/api-keys/" + apikey_tag + + headers = {'Content-Type' :content_type_v3, 'Authorization': jwt} + + print("performing DELETE on {}\n".format(url)) + + resp = requests.delete(url, headers=headers, verify=False) + + if resp.status_code != 204: + raise Exception('Delete API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return diff --git a/snippets/python/api_requests.pyc b/snippets/python/api_requests.pyc new file mode 100644 index 0000000..02c51d3 Binary files /dev/null and b/snippets/python/api_requests.pyc differ diff --git a/snippets/python/apikey_create.py b/snippets/python/apikey_create.py new file mode 100644 index 0000000..ec0a930 --- /dev/null +++ b/snippets/python/apikey_create.py @@ -0,0 +1,113 @@ +import sys +import api_requests + +protocol = "https" +nbmaster = "" +login_username = "" +login_password = "" +login_domainname = "" +login_domaintype = "" +apikey_username = "" +apikey_domainname = "" +apikey_domaintype = "" +expiryindays = "" +description = "" +port = 1556 + +def print_disclaimer(): + print("-------------------------------------------------------------------------------------------------") + print("-- This script requires Python3.5 or higher. --") + print("-- If your current system does not have Python3.5 or higher installed, this will not work. --") + print("-------------------------------------------------------------------------------------------------\n") + print("Executing this library requires some additional python3.5 libraries like \n\t'requests' \n\n") + print("You will, however, require 'requests' library to make the API calls.\n") + print("-------------------------------------------------------------------------------------------------\n\n\n") + +def print_usage(): + print_disclaimer() + print("Example:") + print("python -W ignore apikey_create.py -nbmaster -login_username -login_password [-login_domainname -login_domaintype ] [-apikey_username [-apikey_domainname ] -apikey_domaintype ] -expiryindays -description \n\n\n") + print("-nbmaster : Name of the NetBackup master server\n") + print("-login_username : User name of the user performing action\n") + print("-login_password : Password of the user performing action\n") + print("-login_domainname : Domain name of the user performing action\n") + print("-login_domaintype : Domain type of the user performing action\n") + print("-apikey_username : (Optional) User name of the user for whom API key needs to be generated. Optional in case API key is to be generated for self\n") + print("-apikey_domainname : Domain name of the user for whom API key needs to be generated. Optional in case API key is to be generated for self\n") + print("-apikey_domaintype : Domain type of the user for whom API key needs to be generated. Optional in case API key is to be generated for self\n") + print("-expiryindays : Number of days from today after which API key should expire\n") + print("-description : A textual description to be associated with API key\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global login_username + global login_password + global login_domainname + global login_domaintype + global apikey_username + global apikey_domainname + global apikey_domaintype + global expiryindays + global description + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-login_username": + login_username = sys.argv[i + 1] + elif sys.argv[i] == "-login_password": + login_password = sys.argv[i + 1] + elif sys.argv[i] == "-login_domainname": + login_domainname = sys.argv[i + 1] + elif sys.argv[i] == "-login_domaintype": + login_domaintype = sys.argv[i + 1] + elif sys.argv[i] == "-apikey_username": + apikey_username = sys.argv[i + 1] + elif sys.argv[i] == "-apikey_domainname": + apikey_domainname = sys.argv[i + 1] + elif sys.argv[i] == "-apikey_domaintype": + apikey_domaintype = sys.argv[i + 1] + elif sys.argv[i] == "-expiryindays": + expiryindays = sys.argv[i + 1] + elif sys.argv[i] == "-description": + description = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif login_username == "": + print("Please provide the value for 'login_username'") + exit() + elif login_password == "": + print("Please provide the value for 'login_password'") + exit() + elif expiryindays == "": + print("Please provide the value for 'expiryindays'") + exit() + elif description == "": + print("Please provide the value for 'description'") + exit() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = api_requests.perform_login(login_username, login_password, base_url, login_domainname, login_domaintype) + +response = api_requests.apikey_create(jwt, base_url, expiryindays, description, apikey_username, apikey_domainname, apikey_domaintype) + +apikey = response['data']['attributes']['apiKey'] +apikey_tag = response['data']['id'] +apikey_expiryDateTime = response['data']['attributes']['expiryDateTime'] + +print "Successfully created API Key" +print("API Key:" + apikey) +print("API Key Tag:" + apikey_tag) +print("API Key Expiration Date time:" + apikey_expiryDateTime) diff --git a/snippets/python/apikey_delete.py b/snippets/python/apikey_delete.py new file mode 100644 index 0000000..b49bd23 --- /dev/null +++ b/snippets/python/apikey_delete.py @@ -0,0 +1,82 @@ +import sys +import api_requests + +protocol = "https" +nbmaster = "" +login_password = "" +login_domainname = "" +login_domaintype = "" +apikey_tag = "" +port = 1556 + +def print_disclaimer(): + print("-------------------------------------------------------------------------------------------------") + print("-- This script requires Python3.5 or higher. --") + print("-- If your current system does not have Python3.5 or higher installed, this will not work. --") + print("-------------------------------------------------------------------------------------------------\n") + print("Executing this library requires some additional python3.5 libraries like \n\t'requests' \n\n") + print("You will, however, require 'requests' library to make the API calls.\n") + print("-------------------------------------------------------------------------------------------------\n\n\n") + +def print_usage(): + print_disclaimer() + print("Example:") + print("python -W ignore apikey_create.py -nbmaster -login_username -login_password [-login_domainname -login_domaintype ] -apikey_tag \n") + print("-nbmaster : Name of the NetBackup master server\n") + print("-login_username : User name of the user performing action\n") + print("-login_password : Password of the user performing action\n") + print("-login_domainname : Domain name of the user performing action\n") + print("-login_domaintype : Domain type of the user performing action\n") + print("-apikey_tag : Tag associate with API key to be deleted\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global login_username + global login_password + global login_domainname + global login_domaintype + global apikey_tag + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-login_username": + login_username = sys.argv[i + 1] + elif sys.argv[i] == "-login_password": + login_password = sys.argv[i + 1] + elif sys.argv[i] == "-login_domainname": + login_domainname = sys.argv[i + 1] + elif sys.argv[i] == "-login_domaintype": + login_domaintype = sys.argv[i + 1] + elif sys.argv[i] == "-apikey_tag": + apikey_tag = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif login_username == "": + print("Please provide the value for 'login_username'") + exit() + elif login_password == "": + print("Please provide the value for 'login_password'") + exit() + elif apikey_tag == "": + print("Please provide the value for 'apikey_tag'") + exit() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = api_requests.perform_login(login_username, login_password, base_url, login_domainname, login_domaintype) + +api_requests.apikey_delete(jwt, base_url, apikey_tag) + +print "Successfully deleted API Key with tag " + apikey_tag \ No newline at end of file diff --git a/snippets/python/apikey_usage.py b/snippets/python/apikey_usage.py new file mode 100644 index 0000000..470e5da --- /dev/null +++ b/snippets/python/apikey_usage.py @@ -0,0 +1,80 @@ +import sys +import api_requests +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +apikey = "" + +port = 1556 + +def print_job_details(data): + tab = tt.Texttable() + headings = ['Job ID','Type','State','Status'] + tab.header(headings) + + for data_item in data: + tuple_value = (data_item['attributes']['jobId'], data_item['attributes']['jobType'], data_item['attributes']['state'], data_item['attributes']['status']) + tab.add_row(tuple_value) + + print(tab.draw()) + + +def print_disclaimer(): + print("-------------------------------------------------------------------------------------------------") + print("-- This script requires Python3.5 or higher. --") + print("-- If your current system does not have Python3.5 or higher installed, this will not work. --") + print("-------------------------------------------------------------------------------------------------\n") + print("Executing this library requires some additional python3.5 libraries like \n\t'requests' \n\t'texttable'.\n\n") + print("'texttable' library is just used to show the 'pretty' version of the API response,\nyou might not need it for your netbackup automation.\n") + print("You will, however, require 'requests' library to make the API calls.\n") + print("You can install the dependent libraries using the following commands: ") + print("pip install requests texttable") + print("-------------------------------------------------------------------------------------------------\n\n\n") + print("You can specify the 'nbmaster', 'apikey' as command-line parameters\n") + print_usage() + +def print_usage(): + print("Example:") + print("python -W apikey_usage.py -nbmaster -apikey \n") + print("-nbmaster : Name of the NetBackup master server\n") + print("-apikey : API key to be used instead of JWT\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global apikey + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-apikey": + apikey = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif apikey == "": + print("Please provide the value for 'apikey'") + exit() + +print_disclaimer() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +print("Using API key [" + apikey + "] instead of JWT token to trigger job REST API") +jobs = api_requests.get_netbackup_jobs(apikey, base_url) + +data = jobs['data'] + +if len(data) > 0: + print_job_details(data) diff --git a/snippets/python/cloud/README.md b/snippets/python/cloud/README.md new file mode 100644 index 0000000..64d9a73 --- /dev/null +++ b/snippets/python/cloud/README.md @@ -0,0 +1,18 @@ +### NetBackup API Code Samples for Python + +This directory contains code samples to invoke NetBackup REST APIs using Python. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher +- python 3.5 or higher +- python modules: `requests, sys, argparse, ssl, json` + +#### Executing the snippets in Python + +Use the following commands to run the python samples. +- `python cloud_assets_cleanup.py [-h] --nbu_master_host --nbu_user_name --nbu_password ` \ No newline at end of file diff --git a/snippets/python/cloud/cloud_assets_cleanup.py b/snippets/python/cloud/cloud_assets_cleanup.py new file mode 100644 index 0000000..e926bd6 --- /dev/null +++ b/snippets/python/cloud/cloud_assets_cleanup.py @@ -0,0 +1,155 @@ +#!/usr/bin/python +import requests +import sys +import argparse +import ssl +import json +from datetime import datetime, timedelta + +requests.packages.urllib3.disable_warnings() + +args = () +globals = {} +CLEANUP_TIME = 48 # in hours + +# NetBackup APIs +URL_LOGIN = "/login" +URL_NETBACKUP = "/netbackup" +URL_GET_ASSETS = "/assets" +URL_ASSET_CLEANUP = "/assets/asset-cleanup" +CONTENT_TYPE4 = "application/vnd.netbackup+json;version=4.0" + +# Build the URL to invoke +def buildURL(url, filter = ""): + retURL = "https://" + args.nbu_master_host + URL_NETBACKUP + url + if (filter != ""): + retURL += "?filter=" + filter + return retURL + +# RestClient +def doRestCall(method, url, reqBody = {}): + headers = { + 'Content-Type': CONTENT_TYPE4 + } + if "token" in globals: + headers["Authorization"] = globals["token"] + + if (method == "POST"): + response = requests.post (url, headers = headers, data = json.dumps(reqBody), verify = False) + + if (method == "GET"): + response = requests.get(url, headers=headers, data = json.dumps(reqBody), verify=False) + return response + +# Login to specified NetBackup master server +def loginMaster(): + print ("** Logging in to the NetBackup master host...") + if "token" in globals: + return globals["token"] + + reqBody = { + "userName" : args.nbu_user_name, + "password" : args.nbu_password + } + response = doRestCall("POST", buildURL(URL_LOGIN), reqBody) + if response.status_code == 201: + globals["token"] = response.json()["token"] + return response.json()["token"] + print(" -> Invalid user name or password") + print("** Exiting") + exit(1) + +# Get assets using a filter +def getAssets(): + token = loginMaster() + + print ("** Retrieving assets to cleanup...") + assets = [] + cleanupTime = str((datetime.utcnow() - timedelta(hours = CLEANUP_TIME)).isoformat()) + "Z" + globals["cleanupTime"] = cleanupTime + count = 0 + pageOffset = 0 + while True: + queryFilter = "(lastDiscoveredTime lt " + cleanupTime \ + + " and workloadType eq 'Cloud')" + queryFilter += "&page[offset]=" + str(pageOffset) + "&page[limit]=100" + response = doRestCall("GET", buildURL(URL_GET_ASSETS, queryFilter)) + if response.status_code == 200: + if "data" not in response.json() or len(response.json()["data"]) == 0: + break + assets += response.json()["data"] + pageOffset += 100 + if count == 0: + try: + count = response.json()["meta"]["pagination"]["count"] + except: + pass + else: + if len(assets) == 0: + print (" -> No assets found") + print ("** Exiting") + exit(1) + else: + break + msg = str(len(assets)) + if count != 0: + msg = str(len(assets)) + " / " + str(count) + print (" -> Received " + msg + " stale assets") + globals["assets"] = assets + +def cleanupAssets(): + assets = [] + if "assets" in globals: + assets = globals["assets"] + + if len(assets) == 0: + print(" -> No assets to clean up") + print("** Exiting") + exit(1) + + print ("** Cleaning up " + str(len(assets)) + " assets") + + assetsCleanup = [] + for asset in assets: + assetsCleanup.append(asset["id"]) + + reqBody = {"data": { + "type": "assetCleanup", + "id": "id", + "attributes": { + "cleanupTime": globals["cleanupTime"], + "assetIds": assetsCleanup + } + } + } + response = doRestCall("POST", buildURL(URL_ASSET_CLEANUP), reqBody) + if response.status_code == 204: + print ("** Assets cleaned up successfully") + else: + print("** Unable to clean assets") + print("** Exiting") + +def parseArguments(): + global args + parser = argparse.ArgumentParser() + parser.add_argument('--nbu_master_host', metavar="", \ + help='NetBackup Master Host', required = True) + parser.add_argument('--nbu_user_name', metavar="", + help='NetBackup Username', required = True) + parser.add_argument('--nbu_password', metavar="", \ + help='NetBackup Password', required = True) + args = parser.parse_args() + +def setup(): + try: + _create_unverified_https_context = ssl._create_unverified_context + except AttributeError: + pass + else: + ssl._create_default_https_context = _create_unverified_https_context + +if __name__ == "__main__": + setup() + parseArguments() + getAssets() + cleanupAssets() diff --git a/snippets/python/get_mssql_assets.py b/snippets/python/get_mssql_assets.py new file mode 100644 index 0000000..4ce3d38 --- /dev/null +++ b/snippets/python/get_mssql_assets.py @@ -0,0 +1,107 @@ +## The script can be run with Python 3.5 or higher version. +## The script requires 'requests' library to make the API calls. The library can be installed using the command: pip install requests. + +import api_requests +import argparse +import requests + +def get_usage(): + return ("\nThe command should be run from the parent directory of the 'assets' directory:\n" + "python -Wignore -nbserver -username -password " + "-domainName -domainType [-assetType ] [-assetsFilter ]\n" + "Optional arguments:\n" + "assetType - instance or database or availabilityGroup. Default is 'instance'.\n" + "assetsFilter - OData filter to filter the returned assets (Instance, AvailabilityGroup or database). If not specified, returns all the assets.\n") + +parser = argparse.ArgumentParser(usage = get_usage()) +parser.add_argument('-nbserver', required=True) +parser.add_argument('-username', required=True) +parser.add_argument('-password', required=True) +parser.add_argument('-domainName', required=True) +parser.add_argument('-domainType', required=True) +parser.add_argument('-assetType', default="instance", choices=['instance', 'database', 'availabilityGroup']) +parser.add_argument('-assetsFilter', default="") +args = parser.parse_args() + +nbserver = args.nbserver +username = args.username +password = args.password +domainName = args.domainName +domainType = args.domainType +assetType = args.assetType +assetsFilter = args.assetsFilter + +base_url = "https://" + nbserver + "/netbackup" +mssql_assets_url = base_url + "/asset-service/workloads/mssql/assets" + +default_sort = "commonAssetAttributes.displayName" + +print("\nExecuting the script...") +jwt = api_requests.perform_login(username, password, base_url, domainName, domainType) + +print("\nGetting MSSQL {} assets...".format(assetType)) + +if assetType == "instance": + assetTypeFilter = "(assetType eq 'instance')"; + print("Printing the following MSSQL Instance details: Instance Name, Id, State\n") +elif assetType == "database": + assetTypeFilter = "(assetType eq 'database')"; + print("Printing the following MSSQL details: DatabaseName, Id, InstanceName, AG, assetProtectionDetails\n") +elif assetType == "availabilityGroup": + assetTypeFilter = "(assetType eq 'availabilityGroup')"; + print("Printing the following MSSQL Availabilitygroup details: AvailabilityGroup Name, Server \n") + +if assetsFilter != "": + assetsFilter = assetsFilter + " and " + assetTypeFilter +else: + assetsFilter = assetTypeFilter + +headers = {'Authorization': jwt} + +def get_mssql_assets(): + offset = 0 + next = True + while next: + queryparams = {'page[offset]':offset, 'filter':assetsFilter, 'sort':default_sort} + assets_response = requests.get(mssql_assets_url, headers=headers, params=queryparams, verify=False) + assets = assets_response.json() + + if assets_response.status_code != 200: + print("Mssql Assets API returned status code: {}, response: {}\n".format(assets_response.status_code, assets_response.json())) + raise SystemExit() + + print_assets(assets['data']) + + offset += assets['meta']['pagination']['limit'] + next = assets['meta']['pagination']['hasNext'] + + if len(assets['data']) == 0: + print("No assets returned.") + +def print_assets(assets_data): + for asset in assets_data: + asset_attrs = asset['attributes'] + asset_common_attrs = asset_attrs['commonAssetAttributes'] + ag_attrs = [] + asset_protection_plans = [] + if "activeProtection" in asset_common_attrs : + asset_protection_list = asset_common_attrs['activeProtection']['protectionDetailsList'] + for asset_protection in asset_protection_list: + if (asset_protection['isProtectionPlanCustomized']) == "YES": + asset_protection_plans.append(asset_protection['protectionPlanName']) + else: + asset_protection_plans.append(asset_protection['policyName']) + if "agGroupId" in asset_attrs : + ag_attrs.append(asset_attrs['agName']) + + if assetType == "instance": + print(asset_common_attrs['displayName'], asset['id'], asset_attrs['instanceState'], sep="\t") + elif assetType == "database": + print(asset_common_attrs['displayName'], asset['id'], asset_attrs['instanceName'], ag_attrs, asset_protection_plans, sep="\t") + elif assetType == "availabilityGroup": + print(asset_common_attrs['displayName'], asset['id'], asset_attrs['clusterName'], asset_protection_plans, sep="\t") + + +get_mssql_assets() + +print("\nScript completed!\n") diff --git a/snippets/python/get_mssql_recoverypoints.py b/snippets/python/get_mssql_recoverypoints.py new file mode 100644 index 0000000..f366588 --- /dev/null +++ b/snippets/python/get_mssql_recoverypoints.py @@ -0,0 +1,57 @@ +import sys +import api_requests +import argparse +import json +import texttable as tt + +protocol = "https" +port = 1556 + +def print_rps_details(data): + tab = tt.Texttable(max_width=0) + headings = ['RecoveryPoint ID','Asset ID','Client','Instance','Database','Method','Type','BackupTime'] + tab.header(headings) + + for data_item in data: + tuple_value = (data_item['id'], + data_item['attributes']['assetId'], + data_item['attributes']['clientName'], + data_item['attributes']['extendedAttributes']['sqlInstance'], + data_item['attributes']['extendedAttributes']['databaseName'], + data_item['attributes']['extendedAttributes']['backupMethod'], + data_item['attributes']['extendedAttributes']['backupType'], + data_item['attributes']['backupTime']) + tab.add_row(tuple_value) + + print(tab.draw()) + +def print_usage(): + print("Example:") + print("python -W ignore get_mssql_recoverypoints.py -nbmaster -username -password [-domainname ] [-domaintype ]\n\n\n") + +print_usage() + +parser = argparse.ArgumentParser(usage = print_usage()) +parser.add_argument('-nbmaster', required=True) +parser.add_argument('-username', required=True) +parser.add_argument('-password', required=True) +parser.add_argument('-domainname') +parser.add_argument('-domaintype') +args = parser.parse_args() + +nbmaster = args.nbmaster +username = args.username +password = args.password +domainname = args.domainname +domaintype = args.domaintype + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = api_requests.perform_login(username, password, base_url, domainname, domaintype) + +recoverypoints = api_requests.get_netbackup_mssql_rps(jwt, base_url) + +data = recoverypoints['data'] + +if len(data) > 0: + print_rps_details(data) diff --git a/snippets/python/storage/README.md b/snippets/python/storage/README.md new file mode 100644 index 0000000..04eb6d2 --- /dev/null +++ b/snippets/python/storage/README.md @@ -0,0 +1,34 @@ +### NetBackup API Code Samples for Python + +This directory contains code samples to invoke NetBackup REST APIs using Python. + +#### Disclaimer + +These scripts are only meant to be used as a reference. If you intend to use them in production, use it at your own risk. + +#### Pre-requisites: + +- NetBackup 8.2 or higher +- python 3.5 or higher +- python modules: `requests, texttable` + +#### NOTE - Sample payloads from the snippets\sample-payloads\storage-samples location can be used as input to run the scripts. + +#### Executing the snippets in Python + +Use the following commands to run the python samples. +- `python -W ignore create_disk_pool.py -nbmaster -username -password -payload [-domainname ] [-domaintype ]` +- `python -W ignore create_storage_server.py -nbmaster -username -password -payload [-domainname ] [-domaintype ]` +- `python -W ignore create_storage_unit.py -nbmaster -username -password -payload [-domainname ] [-domaintype ]` +- `python -W ignore delete_disk_pool.py -nbmaster -username -password -dpid [-domainname ] [-domaintype ]` +- `python -W ignore delete_storage_server.py -nbmaster -username -password -stsid [-domainname ] [-domaintype ]` +- `python -W ignore delete_storage_unit.py -nbmaster -username -password -stu_name [-domainname ] [-domaintype ]` +- `python -W ignore get_disk_pool.py -nbmaster -username -password [-domainname ] [-domaintype ]` +- `python -W ignore get_disk_pool_by_id.py -nbmaster -username -password -dpid [-domainname ] [-domaintype ]` +- `python -W ignore get_storage_server.py -nbmaster -username -password [-domainname ] [-domaintype ]` +- `python -W ignore get_storage_unit.py -nbmaster -username -password [-domainname ] [-domaintype ]` +- `python -W ignore get_storage_unit_by_id.py -nbmaster -username -password -stu_name [-domainname ] [-domaintype ]` +- `python -W ignore patch_disk_pool.py -nbmaster -username -password -payload -dpid [-domainname ]` +- `python -W ignore create_storage_server.py -nbmaster -username -password -payload -stsid [-domainname ] [-domaintype ]` +- `python -W ignore patch_storage_unit.py -nbmaster -username -password -payload -stu_name [-domainname ] [-domaintype ]` + diff --git a/snippets/python/storage/create_disk_pool.py b/snippets/python/storage/create_disk_pool.py new file mode 100644 index 0000000..6e79a21 --- /dev/null +++ b/snippets/python/storage/create_disk_pool.py @@ -0,0 +1,70 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore create_disk_pool.py -nbmaster -username -password -payload [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global payload + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-payload": + payload = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + elif payload == "": + print("Please provide the value for 'payload'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +reponse = storage.create_disk_pool(jwt, base_url, payload) + +print(reponse) diff --git a/snippets/python/storage/create_storage_server.py b/snippets/python/storage/create_storage_server.py new file mode 100644 index 0000000..d951959 --- /dev/null +++ b/snippets/python/storage/create_storage_server.py @@ -0,0 +1,74 @@ +import os +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore create_storage_server.py -nbmaster -username -password -payload [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global payload + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-payload": + payload = sys.argv[i + 1] + if os.path.exists(payload): + print + os.path.basename(payload) + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + elif payload == "": + print("Please provide the value for 'payload'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +reponse = storage.create_storage_server(jwt, base_url, payload) + +print(reponse) diff --git a/snippets/python/storage/create_storage_unit.py b/snippets/python/storage/create_storage_unit.py new file mode 100644 index 0000000..244fc1d --- /dev/null +++ b/snippets/python/storage/create_storage_unit.py @@ -0,0 +1,70 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore create_storage_unit.py -nbmaster -username -password -payload [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global payload + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-payload": + payload = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + elif payload == "": + print("Please provide the value for 'payload'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +reponse = storage.create_storage_unit(jwt, base_url, payload) + +print(reponse) diff --git a/snippets/python/storage/delete_disk_pool.py b/snippets/python/storage/delete_disk_pool.py new file mode 100644 index 0000000..6cf1f24 --- /dev/null +++ b/snippets/python/storage/delete_disk_pool.py @@ -0,0 +1,68 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore delete_disk_pool.py -nbmaster -username -password -dpid [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global dpid + +for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-dpid": + dpid = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + +if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() +elif username == "": + print("Please provide the value for 'username'") + exit() +elif password == "": + print("Please provide the value for 'password'") +elif dpid == "": + print("Please provide the value for 'dpid'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +storage.delete_disk_pools(jwt, base_url, dpid) \ No newline at end of file diff --git a/snippets/python/storage/delete_storage_server.py b/snippets/python/storage/delete_storage_server.py new file mode 100644 index 0000000..7f14568 --- /dev/null +++ b/snippets/python/storage/delete_storage_server.py @@ -0,0 +1,71 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + + +def print_usage(): + print("Example:") + print( + "python -W ignore delete_storage_server.py -nbmaster -username -password -stsid [-domainname ] [-domaintype ]\n\n\n") + + +def read_command_line_arguments(): + if len(sys.argv) % 2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global stsid + + +for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-stsid": + stsid = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + +if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() +elif username == "": + print("Please provide the value for 'username'") + exit() +elif password == "": + print("Please provide the value for 'password'") +elif stsid == "": + print("Please provide the value for 'stsid'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) +storage.delete_storage_server(jwt, base_url, stsid) diff --git a/snippets/python/storage/delete_storage_unit.py b/snippets/python/storage/delete_storage_unit.py new file mode 100644 index 0000000..be74f8c --- /dev/null +++ b/snippets/python/storage/delete_storage_unit.py @@ -0,0 +1,72 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + + +def print_usage(): + print("Example:") + print( + "python -W ignore delete_storage_unit.py -nbmaster -username -password -stu_name [-domainname ] [-domaintype ]\n\n\n") + + +def read_command_line_arguments(): + if len(sys.argv) % 2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global stu_name + + +for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-stu_name": + stu_name = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + +if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() +elif username == "": + print("Please provide the value for 'username'") + exit() +elif password == "": + print("Please provide the value for 'password'") +elif stu_name == "": + print("Please provide the value for 'stu_name'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +storage.delete_storage_unit(jwt, base_url, stu_name) \ No newline at end of file diff --git a/snippets/python/storage/get_disk_pool.py b/snippets/python/storage/get_disk_pool.py new file mode 100644 index 0000000..ae92ee4 --- /dev/null +++ b/snippets/python/storage/get_disk_pool.py @@ -0,0 +1,65 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore get_disk_pool.py -nbmaster -username -password [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +jobs = storage.get_disk_pools(jwt, base_url) + +print(jobs) \ No newline at end of file diff --git a/snippets/python/storage/get_disk_pool_by_id.py b/snippets/python/storage/get_disk_pool_by_id.py new file mode 100644 index 0000000..8dfa881 --- /dev/null +++ b/snippets/python/storage/get_disk_pool_by_id.py @@ -0,0 +1,70 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore get_disk_pool_by_id.py -nbmaster -username -password -dpid [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global dpid + +for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-dpid": + dpid = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + +if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() +elif username == "": + print("Please provide the value for 'username'") + exit() +elif password == "": + print("Please provide the value for 'password'") +elif dpid == "": + print("Please provide the value for 'dpid'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +jobs = storage.get_disk_pools_by_id(jwt, base_url, dpid) + +print(jobs) \ No newline at end of file diff --git a/snippets/python/storage/get_storage_server.py b/snippets/python/storage/get_storage_server.py new file mode 100644 index 0000000..c063fe2 --- /dev/null +++ b/snippets/python/storage/get_storage_server.py @@ -0,0 +1,65 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore get_storage_server.py -nbmaster -username -password [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +jobs = storage.get_storage_units(jwt, base_url) + +print(jobs) \ No newline at end of file diff --git a/snippets/python/storage/get_storage_server_by_id.py b/snippets/python/storage/get_storage_server_by_id.py new file mode 100644 index 0000000..4f815a6 --- /dev/null +++ b/snippets/python/storage/get_storage_server_by_id.py @@ -0,0 +1,74 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + + +def print_usage(): + print("Example:") + print( + "python -W ignore get_storage_server_by_id.py -nbmaster -username -password -stsid [-domainname ] [-domaintype ]\n\n\n") + + +def read_command_line_arguments(): + if len(sys.argv) % 2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global stsid + + +for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-stsid": + stsid = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + +if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() +elif username == "": + print("Please provide the value for 'username'") + exit() +elif password == "": + print("Please provide the value for 'password'") +elif stsid == "": + print("Please provide the value for 'stsid'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +jobs = storage.get_storage_server_by_id(jwt, base_url, stsid) + +print(jobs) \ No newline at end of file diff --git a/snippets/python/storage/get_storage_unit.py b/snippets/python/storage/get_storage_unit.py new file mode 100644 index 0000000..0a3ab34 --- /dev/null +++ b/snippets/python/storage/get_storage_unit.py @@ -0,0 +1,63 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 +def print_usage(): + print("Example:") + print("python -W ignore get_storage_unit.py -nbmaster -username -password [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +jobs = storage.get_storage_units(jwt, base_url) +print (jobs) \ No newline at end of file diff --git a/snippets/python/storage/get_storage_unit_by_id.py b/snippets/python/storage/get_storage_unit_by_id.py new file mode 100644 index 0000000..5b9bc38 --- /dev/null +++ b/snippets/python/storage/get_storage_unit_by_id.py @@ -0,0 +1,74 @@ +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + + +def print_usage(): + print("Example:") + print( + "python -W ignore get_storage_unit_by_id.py -nbmaster -username -password -stu_name [-domainname ] [-domaintype ]\n\n\n") + + +def read_command_line_arguments(): + if len(sys.argv) % 2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global stu_name + + +for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-stu_name": + stu_name = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + +if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() +elif username == "": + print("Please provide the value for 'username'") + exit() +elif password == "": + print("Please provide the value for 'password'") +elif stu_name == "": + print("Please provide the value for 'stu_name'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +jobs = storage.get_storage_unit_by_id(jwt, base_url, stu_name) + +print(jobs) \ No newline at end of file diff --git a/snippets/python/storage/patch_disk_pool.py b/snippets/python/storage/patch_disk_pool.py new file mode 100644 index 0000000..d74c5ed --- /dev/null +++ b/snippets/python/storage/patch_disk_pool.py @@ -0,0 +1,76 @@ +import os +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore patch_disk_pool.py -nbmaster -username -password -payload -dpid [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global payload + global dpid + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-payload": + payload = sys.argv[i + 1] + elif sys.argv[i] == "-dpid": + dpid = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + elif payload == "": + print("Please provide the value for 'payload'") + elif dpid == "": + print("Please provide the value for 'dpid'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +reponse = storage.patch_disk_pool(jwt, base_url, payload, dpid) + +print(reponse) diff --git a/snippets/python/storage/patch_storage_server.py b/snippets/python/storage/patch_storage_server.py new file mode 100644 index 0000000..d0693b6 --- /dev/null +++ b/snippets/python/storage/patch_storage_server.py @@ -0,0 +1,76 @@ +import os +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore create_storage_server.py -nbmaster -username -password -payload -stsid [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global payload + global stsid + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-payload": + payload = sys.argv[i + 1] + elif sys.argv[i] == "-stsid": + stsid = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + elif payload == "": + print("Please provide the value for 'payload'") + elif stsid == "": + print("Please provide the value for 'stsid'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +reponse = storage.patch_storage_server(jwt, base_url, payload, stsid) + +print(reponse) diff --git a/snippets/python/storage/patch_storage_unit.py b/snippets/python/storage/patch_storage_unit.py new file mode 100644 index 0000000..bdb5e20 --- /dev/null +++ b/snippets/python/storage/patch_storage_unit.py @@ -0,0 +1,76 @@ +import os +import sys +import storage +import json +import texttable as tt + +protocol = "https" +nbmaster = "" +username = "" +password = "" +domainname = "" +domaintype = "" + +port = 1556 + +def print_usage(): + print("Example:") + print("python -W ignore patch_storage_unit.py -nbmaster -username -password -payload -stu_name [-domainname ] [-domaintype ]\n\n\n") + +def read_command_line_arguments(): + if len(sys.argv)%2 == 0: + print_usage() + exit() + + global nbmaster + global username + global password + global domainname + global domaintype + global payload + global stu_name + + for i in range(1, len(sys.argv), 2): + if sys.argv[i] == "-nbmaster": + nbmaster = sys.argv[i + 1] + elif sys.argv[i] == "-username": + username = sys.argv[i + 1] + elif sys.argv[i] == "-password": + password = sys.argv[i + 1] + elif sys.argv[i] == "-payload": + payload = sys.argv[i + 1] + elif sys.argv[i] == "-stu_name": + stu_name = sys.argv[i + 1] + elif sys.argv[i] == "-domainname": + domainname = sys.argv[i + 1] + elif sys.argv[i] == "-domaintype": + domaintype = sys.argv[i + 1] + else: + print_usage() + exit() + + if nbmaster == "": + print("Please provide the value for 'nbmaster'") + exit() + elif username == "": + print("Please provide the value for 'username'") + exit() + elif password == "": + print("Please provide the value for 'password'") + elif payload == "": + print("Please provide the value for 'payload'") + elif stu_name == "": + print("Please provide the value for 'stu_name'") + exit() + +print_usage() + +read_command_line_arguments() + +base_url = protocol + "://" + nbmaster + ":" + str(port) + "/netbackup" + +jwt = storage.perform_login(username, password, base_url, domainname, domaintype) + +reponse = storage.patch_storage_unit(jwt, base_url, payload, stu_name) + +print(reponse) diff --git a/snippets/python/storage/storage.py b/snippets/python/storage/storage.py new file mode 100644 index 0000000..d86dfa4 --- /dev/null +++ b/snippets/python/storage/storage.py @@ -0,0 +1,284 @@ +import requests + +content_type = "application/vnd.netbackup+json; version=3.0" + + +def perform_login(username, password, base_url, domain_name, domain_type): + url = base_url + "/login" + + if domain_name != "" and domain_type != "": + req_body = {"userName": username, "password": password, "domainName": domain_name, "domainType": domain_type} + else: + req_body = {"userName": username, "password": password} + + headers = {'Content-Type': content_type} + + print("performing POST on {} for user '{}'\n".format(url, req_body['userName'])) + + resp = requests.post(url, headers=headers, json=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Login API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json()['token'] + +def get_storage_units(jwt, base_url): + url = base_url + "/storage/storage-units" + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET STU API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def get_storage_servers(jwt, base_url): + url = base_url + "/storage/storage-servers" + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET STS API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def create_storage_server(jwt, base_url, file_name): + url = base_url + "/storage/storage-servers" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing POST on {}\n".format(url)) + + resp = requests.post(url, headers=headers, data=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Create STS API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +def patch_storage_server(jwt, base_url, file_name, stsid): + url = base_url + "/storage/storage-servers/" + stsid + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing PATCH on {}\n".format(url)) + + resp = requests.patch(url, headers=headers, data=req_body, verify=False) + + + if resp.status_code != 200: + raise Exception('Update STS API failed with status code {} and {}'.format(resp.status_code, resp.json())) + print("\nThe STS is Upadated with status code: {}\n".format(resp.status_code)) + return resp.json() + +def patch_storage_unit(jwt, base_url, file_name, stu_name): + url = base_url + "/storage/storage-units/" +stu_name + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing PATCH on {}\n".format(url)) + + resp = requests.patch(url, headers=headers, data=req_body, verify=False) + + + if resp.status_code != 200: + raise Exception('Update STU API failed with status code {} and {}'.format(resp.status_code, resp.json())) + print("\nThe STU is Upadated with status code: {}\n".format(resp.status_code)) + return resp.json() + +def patch_disk_pool(jwt, base_url, file_name, dpid): + url = base_url + "/storage/disk-pools/" +dpid + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing PATCH on {}\n".format(url)) + + resp = requests.patch(url, headers=headers, data=req_body, verify=False) + + if resp.status_code != 200: + raise Exception('Update DP API failed with status code {} and {}'.format(resp.status_code, resp.json())) + print("\nThe DP is Upadated with status code: {}\n".format(resp.status_code)) + return resp.json() + + +def create_disk_pool(jwt, base_url, file_name): + url = base_url + "/storage/disk-pools" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing POST on {}\n".format(url)) + + resp = requests.post(url, headers=headers, data=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Create DP API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def create_storage_unit(jwt, base_url, file_name): + url = base_url + "/storage/storage-units" + headers = {'Content-Type': content_type, 'Authorization': jwt} + + path = file_name + + req_body = open(path, 'r').read() + + print("performing POST on {}\n".format(url), req_body) + + resp = requests.post(url, headers=headers, data=req_body, verify=False) + + if resp.status_code != 201: + raise Exception('Create STU API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def get_disk_pools(jwt, base_url): + url = base_url + "/storage/disk-pools" + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET DP API failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +def get_disk_pools_by_id(jwt, base_url, dpid): + url = base_url + "/storage/disk-pools/" +dpid + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET DP with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +def get_storage_server_by_id(jwt, base_url, stsid): + url = base_url + "/storage/storage-servers/" +stsid + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET STS with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + +def get_storage_unit_by_id(jwt, base_url, stu_name): + url = base_url + "/storage/storage-units/" +stu_name + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing GET on {}\n".format(url)) + + resp = requests.get(url, headers=headers, params=query_params, verify=False) + + if resp.status_code != 200: + raise Exception('GET STU with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + return resp.json() + + +def delete_storage_server(jwt, base_url, stsid): + url = base_url + "/storage/storage-servers/" +stsid + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing DELETE on {}\n".format(url)) + + resp = requests.delete(url, headers=headers, verify=False) + + if resp.status_code != 204: + raise Exception('DELETE STS with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + print("\nThe STS is deleted with status code: {}\n".format(resp.status_code)) + +def delete_storage_unit(jwt, base_url, stu_name): + url = base_url + "/storage/storage-units/" +stu_name + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing DELETE on {}\n".format(url)) + + resp = requests.delete(url, headers=headers, verify=False) + + if resp.status_code != 204: + raise Exception('DELETE STU with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + print("\nThe STU is deleted with status code: {}\n".format(resp.status_code)) + +def delete_disk_pools(jwt, base_url, dpid): + url = base_url + "/storage/disk-pools/" +dpid + headers = {'Content-Type': content_type, 'Authorization': jwt} + query_params = { + # "page[limit]": 100, #This changes the default page size to 100 + # "filter": "jobType eq 'RESTORE'" #This adds a filter to only show RESTORE Jobs + } + + print("performing DELETE on {}\n".format(url)) + + resp = requests.delete(url, headers=headers, verify=False) + if resp.status_code != 204: + raise Exception('DELETE DP with specific ID failed with status code {} and {}'.format(resp.status_code, resp.json())) + + print("\nThe DP is deleted with status code: {}\n".format(resp.status_code)) \ No newline at end of file diff --git a/snippets/sample-payloads/recovery-samples/post_mssql_pit_singledb_recovery.json b/snippets/sample-payloads/recovery-samples/post_mssql_pit_singledb_recovery.json new file mode 100644 index 0000000..417c8bf --- /dev/null +++ b/snippets/sample-payloads/recovery-samples/post_mssql_pit_singledb_recovery.json @@ -0,0 +1,24 @@ +{ +"data": { + "type": "recoveryRequest", + "attributes": { + "recoveryObject": { + "assetId": "assetid-uuid", + "credentials": { + "domain": "domain", + "userName": "administrator", + "password": "password" + } + }, + "recoveryPoint": "recoverypointid-uuid", + "recoveryOptions": { + "consistencyCheck": "NONE", + "recoveredState": "Recovered", + "replaceDatabase": false, + "trxLogRecoveryOptions": { + "toPointInTime": "2020-03-26T17:55:30.000Z" + } + } + } + } +} diff --git a/snippets/sample-payloads/recovery-samples/post_mssql_singledb_alt_recovery.json b/snippets/sample-payloads/recovery-samples/post_mssql_singledb_alt_recovery.json new file mode 100644 index 0000000..6cfa3d2 --- /dev/null +++ b/snippets/sample-payloads/recovery-samples/post_mssql_singledb_alt_recovery.json @@ -0,0 +1,29 @@ +{ + "data": { + "type":"recoveryRequest", + "attributes": { + "recoveryPoint":"recoverypointid-uuid", + "recoveryObject" : { + "assetId" : "assetid-uuid", + "credentials" : { + "domain" : "domain", + "userName" : "administrator", + "password" : "password" + } + }, + "recoveryOptions" : + { + "replaceDatabase" : false + }, + "alternateRecoveryOptions": + { + "databaseName": "python_test_db", + "instanceName": "SQL2K14", + "client": "client.veritas.com", + "alternateFileLocation": { + "renameAllFilesToSameLocation": "c:\\temp\\" + } + } + } + } +} diff --git a/snippets/sample-payloads/storage-samples/patch_ad_dp_payload.json b/snippets/sample-payloads/storage-samples/patch_ad_dp_payload.json new file mode 100644 index 0000000..ef6f7eb --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_ad_dp_payload.json @@ -0,0 +1,14 @@ +{ + "data": { + "type": "diskPool", + "attributes": { + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 5 + }, + "highWaterMark": 99, + "lowWaterMark": 75, + "diskPoolState": "DOWN" + } + } +} \ No newline at end of file diff --git a/snippets/sample-payloads/storage-samples/patch_ad_sts_payload.json b/snippets/sample-payloads/storage-samples/patch_ad_sts_payload.json new file mode 100644 index 0000000..435cbb1 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_ad_sts_payload.json @@ -0,0 +1,13 @@ +{ +"data": { + "type": "storageServer", + "attributes": { + "advancedDiskAttributes": { + "isPreferredForRestore": false, + "isRequiredForRestore": false, + "isRequiredForDuplication": false + } + + } + } +} \ No newline at end of file diff --git a/snippets/sample-payloads/storage-samples/patch_ad_stu_payload.json b/snippets/sample-payloads/storage-samples/patch_ad_stu_payload.json new file mode 100644 index 0000000..c99ded6 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_ad_stu_payload.json @@ -0,0 +1,10 @@ +{ + "data": { + "type": "storageUnit", + "attributes": { + "maxFragmentSizeMegabytes": 50100, + "maxConcurrentJobs": 8, + "onDemandOnly": true + } + } +} \ No newline at end of file diff --git a/snippets/sample-payloads/storage-samples/patch_cloud_dp_payload.json b/snippets/sample-payloads/storage-samples/patch_cloud_dp_payload.json new file mode 100644 index 0000000..fd2fc16 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_cloud_dp_payload.json @@ -0,0 +1,12 @@ +{ + "data": { + "type": "diskPool", + "attributes": { + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 100 + }, + "diskPoolState": "DP_STATE" + } + } +} diff --git a/snippets/sample-payloads/storage-samples/patch_cloud_sts_payload.json b/snippets/sample-payloads/storage-samples/patch_cloud_sts_payload.json new file mode 100644 index 0000000..87c28a8 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_cloud_sts_payload.json @@ -0,0 +1,22 @@ +{ + "data": { + "type": "storageServer", + "attributes": { + "cloudAttributes": { + "proxyServerEnabled": false, + "serverSideEncryptionEnabled": true, + "readBufferSizeBytes": 419430401, + "writeBufferSizeBytes": 419430401, + "curlDetails": { + "curlLoggingEnabled": true, + "curlTimeOutSeconds": 1200, + "curlConnectionTimeOutSeconds": 600 + }, + "sslDetails": { + "useSSLMode": "NONE", + "checkCertificateRevocation": false + } + } + } + } +} diff --git a/snippets/sample-payloads/storage-samples/patch_cloud_stu_payload.json b/snippets/sample-payloads/storage-samples/patch_cloud_stu_payload.json new file mode 100644 index 0000000..c99ded6 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_cloud_stu_payload.json @@ -0,0 +1,10 @@ +{ + "data": { + "type": "storageUnit", + "attributes": { + "maxFragmentSizeMegabytes": 50100, + "maxConcurrentJobs": 8, + "onDemandOnly": true + } + } +} \ No newline at end of file diff --git a/snippets/sample-payloads/storage-samples/patch_msdp_dp_payload.json b/snippets/sample-payloads/storage-samples/patch_msdp_dp_payload.json new file mode 100644 index 0000000..8b82de9 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_msdp_dp_payload.json @@ -0,0 +1,14 @@ +{ + "data": { + "type": "diskPool", + "attributes": { + "highWaterMark": 90, + "lowWaterMark": 30, + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 100 + }, + "diskPoolState": "DP_STATE" + } + } +} diff --git a/snippets/sample-payloads/storage-samples/patch_msdp_sts_payload.json b/snippets/sample-payloads/storage-samples/patch_msdp_sts_payload.json new file mode 100644 index 0000000..ad31c93 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_msdp_sts_payload.json @@ -0,0 +1,13 @@ +{ + "data": { + "type": "storageServer", + "attributes": { + "msdpAttributes": { + "credentials": { + "userName": "USER_NAME", + "password": "PASSWORD" + } + } + } + } +} diff --git a/snippets/sample-payloads/storage-samples/patch_msdp_stu_payload.json b/snippets/sample-payloads/storage-samples/patch_msdp_stu_payload.json new file mode 100644 index 0000000..28d146b --- /dev/null +++ b/snippets/sample-payloads/storage-samples/patch_msdp_stu_payload.json @@ -0,0 +1,11 @@ +{ + "data": { + "type": "storageUnit", + "attributes": { + "useAnyAvailableMediaServer": true, + "maxFragmentSizeMegabytes": 50100, + "maxConcurrentJobs": 8, + "onDemandOnly": true + } + } +} \ No newline at end of file diff --git a/snippets/sample-payloads/storage-samples/post_ad_dp_payload.json b/snippets/sample-payloads/storage-samples/post_ad_dp_payload.json new file mode 100644 index 0000000..922bf98 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_ad_dp_payload.json @@ -0,0 +1,27 @@ +{ + "data": { + "type": "diskPool", + "attributes": { + "name": "disk-pool1", + "diskVolumes": [ + { + "name": "VOLUME_NAME" + } + ], + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 4 + } + }, + "relationships": { + "storageServers": { + "data": [ + { + "type": "storageServer", + "id": "STORAGE_SERVER_ID" + } + ] + } + } + } +} diff --git a/snippets/sample-payloads/storage-samples/post_ad_sts_payload.json b/snippets/sample-payloads/storage-samples/post_ad_sts_payload.json new file mode 100644 index 0000000..fc87aa9 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_ad_sts_payload.json @@ -0,0 +1,18 @@ +{ +"data": { + "type": "storageServer", + "attributes": { + "name": "STORAGE_SERVER_NAME", + "storageCategory": "ADVANCED_DISK", + "mediaServerDetails": { + "name": "MEDIA_SERVER" + }, + "advancedDiskAttributes": { + "isPreferredForRestore": true, + "isRequiredForRestore": true, + "isRequiredForDuplication": false + } + } + } +} + diff --git a/snippets/sample-payloads/storage-samples/post_ad_stu_payload.json b/snippets/sample-payloads/storage-samples/post_ad_stu_payload.json new file mode 100644 index 0000000..a78837a --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_ad_stu_payload.json @@ -0,0 +1,20 @@ +{ + "data": { + "type": "storageUnit", + "attributes": { + "name": "my-stu", + "useAnyAvailableMediaServer": true, + "maxFragmentSizeMegabytes": 51200, + "maxConcurrentJobs": 5, + "onDemandOnly": true + }, + "relationships": { + "diskPool": { + "data": { + "type": "diskPool", + "id": "DISK_POOL_ID" + } + } + } + } +} \ No newline at end of file diff --git a/snippets/sample-payloads/storage-samples/post_cloud_dp_payload.json b/snippets/sample-payloads/storage-samples/post_cloud_dp_payload.json new file mode 100644 index 0000000..922bf98 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_cloud_dp_payload.json @@ -0,0 +1,27 @@ +{ + "data": { + "type": "diskPool", + "attributes": { + "name": "disk-pool1", + "diskVolumes": [ + { + "name": "VOLUME_NAME" + } + ], + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 4 + } + }, + "relationships": { + "storageServers": { + "data": [ + { + "type": "storageServer", + "id": "STORAGE_SERVER_ID" + } + ] + } + } + } +} diff --git a/snippets/sample-payloads/storage-samples/post_cloud_sts_payload.json b/snippets/sample-payloads/storage-samples/post_cloud_sts_payload.json new file mode 100644 index 0000000..83d67ca --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_cloud_sts_payload.json @@ -0,0 +1,31 @@ +{ + "data": { + "type": "storageServer", + "attributes": { + "name": "amazonstss.com", + "storageCategory": "CLOUD", + "mediaServerDetails": { + "name": "MEDIA_SERVER" + }, + "cloudAttributes": { + "providerId": "amazon", + "compressionEnabled": true, + "s3RegionDetails": [ + { + "serviceHost": "SERVICE-HOST", + "regionName": "REGION_NAME", + "regionId": "REGION_ID" + } + ], + "cloudCredentials": { + "authType": "ACCESS_KEY", + "accessKeyDetails": { + "userName": "USER_ID", + "password": "PASSWORD" + } + } + } + } + } +} + diff --git a/snippets/sample-payloads/storage-samples/post_cloud_stu_payload.json b/snippets/sample-payloads/storage-samples/post_cloud_stu_payload.json new file mode 100644 index 0000000..39b75f2 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_cloud_stu_payload.json @@ -0,0 +1,20 @@ +{ + "data": { + "type": "storageUnit", + "attributes": { + "name": "cloud-stu", + "useAnyAvailableMediaServer": true, + "maxFragmentSizeMegabytes": 50000, + "maxConcurrentJobs": 10, + "onDemandOnly": true + }, + "relationships": { + "diskPool": { + "data" : { + "type": "diskPool", + "id": "DISK_POOL_ID" + } + } + } +} +} \ No newline at end of file diff --git a/snippets/sample-payloads/storage-samples/post_msdp_dp_payload.json b/snippets/sample-payloads/storage-samples/post_msdp_dp_payload.json new file mode 100644 index 0000000..f6ef511 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_msdp_dp_payload.json @@ -0,0 +1,27 @@ +{ + "data": { + "type": "diskPool", + "attributes": { + "name": "msdp-dp1", + "diskVolumes": [ + { + "name":"PureDiskVolume" + } + ], + "maximumIoStreams": { + "limitIoStreams": true, + "streamsPerVolume": 2 + } + }, + "relationships":{ + "storageServers": { + "data": [ + { + "type": "storageServer", + "id": "STORAGE_SERVER_ID" + } + ] + } + } + } + } \ No newline at end of file diff --git a/snippets/sample-payloads/storage-samples/post_msdp_sts_payload.json b/snippets/sample-payloads/storage-samples/post_msdp_sts_payload.json new file mode 100644 index 0000000..f8f7e32 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_msdp_sts_payload.json @@ -0,0 +1,22 @@ +{ +"data": { + "type": "storageServer", + "attributes": { + "name": "STORAGE_SERVER", + "storageCategory": "MSDP", + "mediaServerDetails": { + "name": "MEDIA_SERVER" + }, + "encryptionEnabled": true, + "msdpAttributes": { + "storagePath": "STORAGE_PATH", + "credentials": { + "userName": "MSDP_USERID", + "password": "MSDP_PASSWORD" + } + } + } + } + +} + diff --git a/snippets/sample-payloads/storage-samples/post_msdp_stu_payload.json b/snippets/sample-payloads/storage-samples/post_msdp_stu_payload.json new file mode 100644 index 0000000..19fa667 --- /dev/null +++ b/snippets/sample-payloads/storage-samples/post_msdp_stu_payload.json @@ -0,0 +1,20 @@ +{ + "data": { + "type": "storageUnit", + "attributes": { + "name": "STORAGE_UNIT", + "useAnyAvailableMediaServer": true, + "maxFragmentSizeMegabytes": 50000, + "maxConcurrentJobs": 10, + "onDemandOnly": true + }, + "relationships": { + "diskPool": { + "data": { + "type": "diskPool", + "id": "DISK_POOL_ID" + } + } + } + } +} diff --git a/vmware_asset_group_add_FolderFilter b/vmware_asset_group_add_FolderFilter new file mode 100644 index 0000000..bb74ad2 --- /dev/null +++ b/vmware_asset_group_add_FolderFilter @@ -0,0 +1,44 @@ +--- +### Requirements +# inputs from parent - {{login_token}}, +# inputs from inventory - {{master}}, {{vcenter}}, {{baseurl}}, {{contenttype}} +# outputs {{protectionplan}}, {{pp_id}} + + - name: add corp folder protection plan + uri: + url: "{{baseurl}}asset-groups" + method: post + body_format: json + headers: + authorization: "{{login_token}}" + content-type: "{{contenttype}}" + body: + data: + attributes: + displayName: "{{item.seg}}-folder-test" + description: "selects all {{item.seg}} folders for all vcenters in region" + oDataQueryFilter: "contains(extendedAttributes/vmFolder, '{{item.seg}}') or (contains(extendedAttributes/vmFolder, '{{item.type}}'))" + vipQueryFilter: "((VMFolder Contains '{{item.seg}}') OR (VMFolder Contains '{{item.type}}')) AND ((vCenter Equal '{{vcenter}}') OR (ESXserver Equal '{{vcenter}}'))" + assetType: "Virtual Machine" + workloadType: VMware + filterConstraint: "{{vcenter}}" + type: assetGroup + port: 0 + validate: true + status_code: 201 + validate_certs: no + return_content: yes + with_items: + - {seg: 'BU1', type: 'Image Backup' } + - {seg: 'BU2', type: 'Image Backup' } + - {seg: 'BU3', type: 'Image Backup' } + register: protectionplan + ignore_errors: true + + - name : debug protectionplan var + debug: + msg: "{{protectionplan}}" + + - name: Set Fact - Protection Plan ID + set_fact: + pp_id: "{{protectionplan.json.data.id}}"