diff --git a/APIFiles/APIClient.go b/APIFiles/APIClient.go index 422e272..ff24cac 100644 --- a/APIFiles/APIClient.go +++ b/APIFiles/APIClient.go @@ -26,6 +26,7 @@ import ( "reflect" "strconv" "strings" + "sync" "time" ) @@ -40,6 +41,7 @@ const ( WebContext string = "web_api" DefaultProxyPort = -1 DefaultProxyHost = "" + AutoPublishBatchSize int = 100 ) // Check Point API Client (Management/GAIA) @@ -59,11 +61,17 @@ type ApiClient struct { debugFile string httpDebugLevel string context string - autoPublish bool timeout time.Duration sleep time.Duration userAgent string cloudMgmtId string + autoPublishBatchSize int + activeCallsLock sync.Mutex + autoPublishLock sync.Mutex + totalCallsLock sync.Mutex + duringPublish bool + activeCallsCtr int + totalCallsCtr int } // Api Client constructor @@ -116,7 +124,7 @@ func APIClient(apiCA ApiClientArgs) *ApiClient { debugFile: apiCA.DebugFile, httpDebugLevel: apiCA.HttpDebugLevel, context: apiCA.Context, - autoPublish: apiCA.AutoPublish, + autoPublishBatchSize: apiCA.AutoPublishBatchSize, timeout: apiCA.Timeout, sleep: apiCA.Sleep, userAgent: apiCA.UserAgent, @@ -134,10 +142,6 @@ func (c *ApiClient) GetContext() string { return c.context } -func (c *ApiClient) GetAutoPublish() bool { - return c.autoPublish -} - // Returns the fingerprint of API client func (c *ApiClient) getFingerprint() string { return c.fingerprint @@ -178,6 +182,36 @@ func (c *ApiClient) GetSessionID() string { return c.sid } +// Returns number of batch size +func (c *ApiClient) GetAutoPublishBatchSize() int { + return c.autoPublishBatchSize +} + +func (c *ApiClient) SetAutoPublishBatchSize(autoPublishBatchSize int) { + c.autoPublishBatchSize = autoPublishBatchSize +} + +func (c *ApiClient) increaseActiveCalls() { + c.activeCallsLock.Lock() + c.activeCallsCtr++ + c.activeCallsLock.Unlock() +} + +func (c *ApiClient) decreaseActiveCalls() { + c.activeCallsLock.Lock() + c.activeCallsCtr-- + c.activeCallsLock.Unlock() +} + +func (c *ApiClient) ResetTotalCallsCounter() { + c.totalCallsCtr = 0 +} + +func (c *ApiClient) DisableAutoPublish() { + c.autoPublishBatchSize = -1 + c.totalCallsCtr = 0 +} + // Deprecated: Do not use. func (c *ApiClient) Login(username string, password string, continueLastSession bool, domain string, readOnly bool, payload string) (APIResponse, error) { credentials := map[string]interface{}{ @@ -253,7 +287,7 @@ func (c *ApiClient) commonLoginLogic(credentials map[string]interface{}, continu } } - loginRes, errCall := c.ApiCall("login", credentials, "", false, false) + loginRes, errCall := c.apiCall("login", credentials, "", false, c.IsProxyUsed(), true) if errCall != nil { return loginRes, errCall } @@ -285,6 +319,14 @@ side-effects: updates the class's uid and server variables */ func (c *ApiClient) ApiCall(command string, payload map[string]interface{}, sid string, waitForTask bool, useProxy bool) (APIResponse, error) { + return c.apiCall(command,payload,sid,waitForTask,useProxy,false) +} + +func (c *ApiClient) ApiCallSimple(command string, payload map[string]interface{}) (APIResponse, error) { + return c.apiCall(command, payload, c.sid,true, c.IsProxyUsed(),false) +} + +func (c *ApiClient) apiCall(command string, payload map[string]interface{}, sid string, waitForTask bool, useProxy bool, internal bool) (APIResponse, error) { fp, errFP := getFingerprint(c.server, c.port) if errFP != nil { return APIResponse{}, errFP @@ -357,21 +399,55 @@ func (c *ApiClient) ApiCall(command string, payload map[string]interface{}, sid req.Header.Set("X-chkp-sid", sid) } + if !internal && c.autoPublishBatchSize > 0 { + waitToRun := true + for waitToRun { + if c.totalCallsCtr + 1 <= c.autoPublishBatchSize && !c.duringPublish { + c.totalCallsLock.Lock() + if c.totalCallsCtr + 1 <= c.autoPublishBatchSize && !c.duringPublish { + c.totalCallsCtr++ + waitToRun = false + } + c.totalCallsLock.Unlock() + } + if waitToRun { + time.Sleep(time.Second) + } + } + c.increaseActiveCalls() + } + response, err := client.client.Do(req) + if err != nil { + if !internal && c.autoPublishBatchSize > 0 { + c.decreaseActiveCalls() + } return APIResponse{}, err } res, err := fromHTTPResponse(response, "") if err != nil { + if !internal && c.autoPublishBatchSize > 0 { + c.decreaseActiveCalls() + } return APIResponse{}, err } if !res.Success { + resCode := "" + resMsg := "" + if code := res.GetData()["code"]; code != nil { + resCode = code.(string) + } + if msg := res.GetData()["message"]; msg != nil { + resMsg = msg.(string) + } + fullErrorMsg := "failed to execute API call" + "\nStatus: " + res.StatusCode + - "\nCode: " + res.GetData()["code"].(string) + - "\nMessage: " + res.GetData()["message"].(string) + "\nCode: " + resCode + + "\nMessage: " + resMsg if errorMsg := res.data["errors"]; errorMsg != nil { fullErrorMsg += "\nErrors: " @@ -419,6 +495,9 @@ func (c *ApiClient) ApiCall(command string, payload map[string]interface{}, sid if _, ok := res.data["task-id"]; ok { res, err = c.waitForTask(res.data["task-id"].(string)) if err != nil { + if !internal && c.autoPublishBatchSize > 0 { + c.decreaseActiveCalls() + } return APIResponse{}, err } } else if _, ok := res.data["tasks"]; ok { @@ -428,6 +507,36 @@ func (c *ApiClient) ApiCall(command string, payload map[string]interface{}, sid } } } + + if !internal && c.autoPublishBatchSize > 0 { + c.decreaseActiveCalls() + if c.totalCallsCtr > 0 && c.totalCallsCtr % c.autoPublishBatchSize == 0 && !c.duringPublish { + c.autoPublishLock.Lock() + if c.totalCallsCtr > 0 && c.totalCallsCtr % c.autoPublishBatchSize == 0 && !c.duringPublish { + c.duringPublish = true + c.autoPublishLock.Unlock() + for c.activeCallsCtr > 0 { + // Waiting for other calls to finish + fmt.Println("Waiting to start auto publish (Active calls " + strconv.Itoa(c.activeCallsCtr) + ")") + time.Sleep(time.Second) + } + // Going to publish + fmt.Println("Start auto publish...") + publishRes, _ := c.apiCall("publish", map[string]interface{}{},c.GetSessionID(),true,c.IsProxyUsed(), true) + + if !publishRes.Success { + fmt.Println("Auto publish failed. Message: " + publishRes.ErrorMsg) + }else{ + fmt.Println("Auto publish finished successfully") + } + c.totalCallsCtr = 0 + c.duringPublish = false + }else{ + c.autoPublishLock.Unlock() + } + } + } + return res, nil } @@ -527,7 +636,7 @@ func (c *ApiClient) genApiQuery(command string, detailsLevel string, containerKe payload["limit"] = objLimit payload["offset"] = iterations * objLimit payload["details-level"] = detailsLevel - apiRes, err := c.ApiCall(command, payload, "", false, false) + apiRes, err := c.apiCall(command, payload, c.sid, false, c.IsProxyUsed(), true) if err != nil { print(err.Error()) @@ -581,7 +690,7 @@ func (c *ApiClient) genApiQuery(command string, detailsLevel string, containerKe payload["limit"] = objLimit payload["offset"] = iterations * objLimit payload["details-level"] = detailsLevel - apiRes, err = c.ApiCall(command, payload, "", false, false) + apiRes, err = c.apiCall(command, payload, c.sid, false, c.IsProxyUsed(), true) if err != nil { print("Error communicating with server, please check your connection.") @@ -613,7 +722,7 @@ func (c *ApiClient) waitForTask(taskId string) (APIResponse, error) { payload := map[string]interface{}{"task-id": taskId, "details-level": "full"} for !taskComplete { - taskResult, err = c.ApiCall("show-task", payload, c.sid, false, false) + taskResult, err = c.apiCall("show-task", payload, c.sid, false, c.IsProxyUsed(), true) if err != nil { return APIResponse{}, err @@ -625,7 +734,7 @@ func (c *ApiClient) waitForTask(taskId string) (APIResponse, error) { if attemptsCounter < 5 { attemptsCounter++ time.Sleep(c.sleep) - taskResult, err = c.ApiCall("show-task", payload, c.sid, false, false) + taskResult, err = c.apiCall("show-task", payload, c.sid, false, c.IsProxyUsed(), true) if err != nil { return APIResponse{}, err @@ -679,7 +788,7 @@ func (c *ApiClient) waitForTasks(taskObjects []interface{}) APIResponse { "task-id": tasks, "details-level": "full", } - taskRes, err := c.ApiCall("show-task", payload, c.GetSessionID(), false, c.proxyHost != "") + taskRes, err := c.apiCall("show-task", payload, c.GetSessionID(), false, c.IsProxyUsed(), true) if err != nil { fmt.Println("Problem showing tasks, try again") diff --git a/APIFiles/APIClientArgs.go b/APIFiles/APIClientArgs.go index c58b809..a03b73d 100644 --- a/APIFiles/APIClientArgs.go +++ b/APIFiles/APIClientArgs.go @@ -16,11 +16,11 @@ type ApiClientArgs struct { AcceptServerCertificate bool DebugFile string Context string - AutoPublish bool Timeout time.Duration Sleep time.Duration UserAgent string CloudMgmtId string + AutoPublishBatchSize int } /* @@ -39,8 +39,12 @@ AcceptServerCertificate: indicates that the client should automatically accept a DebugFile: name of debug file Context: which API to use - Management API = web_api (default) or GAIA API = gaia_api Timeout: HTTP Client timeout value +Sleep: Interval size in seconds of the task update +UserAgent: User agent will be use in api call request header +CloudMgmtId: Smart-1 Cloud management UID +AutoPublishBatchSize: Number of batch size for auto publish */ -func APIClientArgs(port int, fingerprint string, sid string, server string, proxyHost string, proxyPort int, apiVersion string, ignoreServerCertificate bool, acceptServerCertificate bool, debugFile string, context string, timeout time.Duration, sleep time.Duration, userAgent string, cloudMgmtId string) ApiClientArgs { +func APIClientArgs(port int, fingerprint string, sid string, server string, proxyHost string, proxyPort int, apiVersion string, ignoreServerCertificate bool, acceptServerCertificate bool, debugFile string, context string, timeout time.Duration, sleep time.Duration, userAgent string, cloudMgmtId string, autoPublishBatchSize int) ApiClientArgs { return ApiClientArgs{ Port: port, @@ -58,5 +62,6 @@ func APIClientArgs(port int, fingerprint string, sid string, server string, prox Sleep: sleep, UserAgent: userAgent, CloudMgmtId: cloudMgmtId, + AutoPublishBatchSize: autoPublishBatchSize, } } diff --git a/Examples/add_access_rule.go b/Examples/add_access_rule.go index 6cafa4f..49d3f79 100644 --- a/Examples/add_access_rule.go +++ b/Examples/add_access_rule.go @@ -1,7 +1,7 @@ package Examples import ( - api "../APIFiles" + api "cp-mgmt-api-go-sdk/APIFiles" "fmt" "os" ) @@ -21,7 +21,7 @@ func AddAccessRule() { fmt.Printf("Enter password: ") fmt.Scanln(&password) - args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "") + args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "", -1) client := api.APIClient(args) fmt.Printf("Enter the name of the access rule: ") diff --git a/Examples/add_host.go b/Examples/add_host.go index f3c68ac..78977bf 100644 --- a/Examples/add_host.go +++ b/Examples/add_host.go @@ -1,7 +1,7 @@ package Examples import ( - api "../APIFiles" + api "cp-mgmt-api-go-sdk/APIFiles" "fmt" "os" ) @@ -20,7 +20,7 @@ func AddHost() { fmt.Printf("Enter password: ") fmt.Scanln(&password) - args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "") + args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "", -1) client := api.APIClient(args) diff --git a/Examples/auto_publish.go b/Examples/auto_publish.go new file mode 100644 index 0000000..4126918 --- /dev/null +++ b/Examples/auto_publish.go @@ -0,0 +1,99 @@ +package Examples + +import ( + api "cp-mgmt-api-go-sdk/APIFiles" + "fmt" + "os" + "strconv" + "time" +) + +func AutoPublish() { + var apiServer string + var username string + var password string + + fmt.Printf("Enter server IP address or hostname: ") + fmt.Scanln(&apiServer) + + fmt.Printf("Enter username: ") + fmt.Scanln(&username) + + fmt.Printf("Enter password: ") + fmt.Scanln(&password) + + args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "", api.AutoPublishBatchSize) + + client := api.APIClient(args) + + if ok, _ := client.CheckFingerprint(); !ok { + fmt.Println("Could not get the server's fingerprint - Check connectivity with the server") + os.Exit(1) + } + + loginRes, err := client.ApiLogin(username, password,false, "", false, nil) + if err != nil { + fmt.Println("Login error") + os.Exit(1) + } + + if !loginRes.Success { + fmt.Println("Login failed: " + loginRes.ErrorMsg) + os.Exit(1) + } + + numOfThreads := 10 + numOfObjectsToCreate := 100 + threadNamePrefix := "auto-publish-thread" + + fmt.Println("Start auto publish program. Number of threads " + strconv.Itoa(numOfThreads)) + for i := 0; i < numOfThreads; i++ { + go run(threadNamePrefix + strconv.Itoa(i), numOfObjectsToCreate, client) + } + + time.Sleep(time.Minute * 3) + + client.ApiCallSimple("publish", map[string]interface{}{}) + + fmt.Println("Finished to create all objects") + + deleteObjects(client, threadNamePrefix) + + client.ApiCallSimple("logout", map[string]interface{}{}) + + fmt.Println("Auto publish example finished successfully") +} + +func run(threadName string, numOfObjectsToCreate int, apiClient interface{}){ + fmt.Println("Start thread -> " + threadName) + client := apiClient.(*api.ApiClient) + for i := 0; i < numOfObjectsToCreate; i++ { + groupName := threadName + "-group" + strconv.Itoa(i) + res, err := client.ApiCallSimple("add-group", map[string]interface{}{"name":groupName}) + if err != nil { + fmt.Println("Error: " + err.Error()) + } + if !res.Success { + fmt.Println("Failed to add group: " + res.ErrorMsg) + } + } + fmt.Println(threadName + " finished") +} + +func deleteObjects(client *api.ApiClient, objPrefix string) { + res, _ := client.ApiQuery("show-groups", "standard", "", true, map[string]interface{}{"filter": objPrefix}) + if res.Success { + client.ResetTotalCallsCounter() + objects := res.GetData()["objects"].([]map[string]interface{}) + fmt.Println("Delete " + strconv.Itoa(len(objects)) + " objects...") + if len(objects) > 0 { + for i := 0 ; i < len(objects) ; i++ { + client.ApiCallSimple("delete-group", map[string]interface{}{"uid":objects[i]["uid"]}) + } + client.ApiCallSimple("publish", map[string]interface{}{}) + fmt.Println("Groups deleted") + }else{ + fmt.Println("Not found groups to delete") + } + } +} diff --git a/Examples/discard_sessions.go b/Examples/discard_sessions.go index b181a04..33f95a8 100644 --- a/Examples/discard_sessions.go +++ b/Examples/discard_sessions.go @@ -1,7 +1,7 @@ package Examples import ( - api "../APIFiles" + api "cp-mgmt-api-go-sdk/APIFiles" "fmt" "os" ) @@ -21,7 +21,7 @@ func DiscardSessions() { fmt.Printf("Enter password: ") fmt.Scanln(&password) - args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "") + args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "", -1) client := api.APIClient(args) diff --git a/Examples/find_dup_ip.go b/Examples/find_dup_ip.go index 158406b..032e5b5 100644 --- a/Examples/find_dup_ip.go +++ b/Examples/find_dup_ip.go @@ -1,7 +1,7 @@ package Examples import ( - api "../APIFiles" + api "cp-mgmt-api-go-sdk/APIFiles" "fmt" "os" ) @@ -20,7 +20,7 @@ func DupIp() { var pass string fmt.Scanln(&pass) - args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "") + args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "", -1) client := api.APIClient(args) diff --git a/Examples/show_hosts.go b/Examples/show_hosts.go index 5408488..8c4c80b 100644 --- a/Examples/show_hosts.go +++ b/Examples/show_hosts.go @@ -1,7 +1,7 @@ package Examples import ( - api "../APIFiles" + api "cp-mgmt-api-go-sdk/APIFiles" "fmt" "os" ) @@ -21,7 +21,7 @@ func ShowHosts() { fmt.Printf("Enter password: ") fmt.Scanln(&password) - args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "") + args := api.APIClientArgs(api.DefaultPort, "", "", apiServer, "", -1, "", false, false, "deb.txt", api.WebContext, api.TimeOut, api.SleepTime, "", "", -1) client := api.APIClient(args) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bd0975c --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module cp-mgmt-api-go-sdk + +go 1.17 diff --git a/main.go b/main.go index 7ed81a2..43e79da 100644 --- a/main.go +++ b/main.go @@ -1,12 +1,16 @@ package main import ( - "./Examples" + Examples "cp-mgmt-api-go-sdk/Examples" "fmt" "os" ) func main(){ + if len(os.Args) < 2 { + fmt.Println("Operation not found. Optional operations are rule/discard/add_host/show_hosts/dup_ip/auto_publish") + os.Exit(0) + } switch os.Args[1] { case "discard": @@ -19,7 +23,9 @@ func main(){ Examples.ShowHosts() case "dup_ip": Examples.DupIp() + case "auto_publish": + Examples.AutoPublish() default: - fmt.Println("Operation not supported. Optional operations are rule/discard/add_host/show_hosts/dup_ip") + fmt.Println("Operation not supported. Optional operations are rule/discard/add_host/show_hosts/dup_ip/auto_publish") } }