catocli 2.0.5__py3-none-any.whl → 2.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of catocli might be problematic. Click here for more details.

Files changed (365) hide show
  1. catocli/Utils/clidriver.py +32 -4
  2. catocli/Utils/version_checker.py +1 -1
  3. catocli/__init__.py +1 -1
  4. catocli/parsers/custom/export_sites/export_sites.py +18 -1
  5. catocli/parsers/custom/import_rules_to_tf/import_rules_to_tf.py +13 -2
  6. catocli/parsers/custom/import_sites_to_tf/__init__.py +3 -1
  7. catocli/parsers/custom/import_sites_to_tf/import_sites_to_tf.py +79 -6
  8. catocli/parsers/custom_private/__init__.py +134 -0
  9. catocli/parsers/mutation_accountManagement/__init__.py +13 -0
  10. catocli/parsers/mutation_accountManagement_disableAccount/README.md +16 -0
  11. catocli/parsers/mutation_groups/README.md +7 -0
  12. catocli/parsers/mutation_groups/__init__.py +48 -0
  13. catocli/parsers/mutation_groups_createGroup/README.md +18 -0
  14. catocli/parsers/mutation_groups_deleteGroup/README.md +18 -0
  15. catocli/parsers/mutation_groups_updateGroup/README.md +18 -0
  16. catocli/parsers/mutation_site/__init__.py +104 -0
  17. catocli/parsers/mutation_site_assignSiteBwLicense/README.md +17 -0
  18. catocli/parsers/mutation_site_removeSecondaryAwsVSocket/README.md +17 -0
  19. catocli/parsers/mutation_site_removeSecondaryAzureVSocket/README.md +17 -0
  20. catocli/parsers/mutation_site_removeSiteBwLicense/README.md +17 -0
  21. catocli/parsers/mutation_site_replaceSiteBwLicense/README.md +17 -0
  22. catocli/parsers/mutation_site_updateSecondaryAwsVSocket/README.md +17 -0
  23. catocli/parsers/mutation_site_updateSecondaryAzureVSocket/README.md +17 -0
  24. catocli/parsers/mutation_site_updateSiteBwLicense/README.md +17 -0
  25. catocli/parsers/mutation_site_updateSiteGeneralDetails/README.md +1 -1
  26. catocli/parsers/mutation_sites/__init__.py +104 -0
  27. catocli/parsers/mutation_sites_assignSiteBwLicense/README.md +17 -0
  28. catocli/parsers/mutation_sites_removeSecondaryAwsVSocket/README.md +17 -0
  29. catocli/parsers/mutation_sites_removeSecondaryAzureVSocket/README.md +17 -0
  30. catocli/parsers/mutation_sites_removeSiteBwLicense/README.md +17 -0
  31. catocli/parsers/mutation_sites_replaceSiteBwLicense/README.md +17 -0
  32. catocli/parsers/mutation_sites_updateSecondaryAwsVSocket/README.md +17 -0
  33. catocli/parsers/mutation_sites_updateSecondaryAzureVSocket/README.md +17 -0
  34. catocli/parsers/mutation_sites_updateSiteBwLicense/README.md +17 -0
  35. catocli/parsers/mutation_sites_updateSiteGeneralDetails/README.md +1 -1
  36. catocli/parsers/parserApiClient.py +444 -9
  37. catocli/parsers/query_eventsFeed/README.md +1 -1
  38. catocli/parsers/query_groups/README.md +7 -0
  39. catocli/parsers/query_groups/__init__.py +54 -0
  40. catocli/parsers/query_groups_group/README.md +7 -0
  41. catocli/parsers/query_groups_groupList/README.md +18 -0
  42. catocli/parsers/query_groups_group_members/README.md +18 -0
  43. catocli/parsers/query_groups_whereUsed/README.md +17 -0
  44. catocli/parsers/query_popLocations/README.md +17 -0
  45. catocli/parsers/query_popLocations/__init__.py +16 -0
  46. catocli/parsers/query_site/__init__.py +26 -0
  47. catocli/parsers/query_site_secondaryAwsVSocket/README.md +17 -0
  48. catocli/parsers/query_site_secondaryAzureVSocket/README.md +17 -0
  49. catocli/parsers/query_socketPortMetrics/README.md +23 -0
  50. catocli/parsers/query_socketPortMetrics/__init__.py +16 -0
  51. catocli/parsers/query_socketPortMetricsTimeSeries/README.md +24 -0
  52. catocli/parsers/query_socketPortMetricsTimeSeries/__init__.py +16 -0
  53. {catocli-2.0.5.dist-info → catocli-2.1.1.dist-info}/METADATA +3 -2
  54. {catocli-2.0.5.dist-info → catocli-2.1.1.dist-info}/RECORD +253 -300
  55. {catocli-2.0.5.dist-info → catocli-2.1.1.dist-info}/WHEEL +1 -1
  56. {catocli-2.0.5.dist-info → catocli-2.1.1.dist-info}/top_level.txt +0 -2
  57. graphql_client/api/call_api.py +20 -2
  58. models/mutation.accountManagement.addAccount.json +97 -0
  59. models/mutation.accountManagement.disableAccount.json +545 -0
  60. models/mutation.accountManagement.removeAccount.json +102 -3
  61. models/mutation.accountManagement.updateAccount.json +97 -0
  62. models/mutation.admin.addAdmin.json +6 -9
  63. models/mutation.container.delete.json +2 -2
  64. models/mutation.container.fqdn.addValues.json +3 -3
  65. models/mutation.container.fqdn.createFromFile.json +3 -3
  66. models/mutation.container.fqdn.removeValues.json +3 -3
  67. models/mutation.container.fqdn.updateFromFile.json +3 -3
  68. models/mutation.container.ipAddressRange.addValues.json +3 -3
  69. models/mutation.container.ipAddressRange.createFromFile.json +3 -3
  70. models/mutation.container.ipAddressRange.removeValues.json +3 -3
  71. models/mutation.container.ipAddressRange.updateFromFile.json +3 -3
  72. models/mutation.groups.createGroup.json +3178 -0
  73. models/mutation.groups.deleteGroup.json +2758 -0
  74. models/mutation.groups.updateGroup.json +4429 -0
  75. models/mutation.hardware.updateHardwareShipping.json +30 -10
  76. models/mutation.policy.appTenantRestriction.addRule.json +33 -33
  77. models/mutation.policy.appTenantRestriction.addSection.json +4 -4
  78. models/mutation.policy.appTenantRestriction.createPolicyRevision.json +33 -33
  79. models/mutation.policy.appTenantRestriction.discardPolicyRevision.json +33 -33
  80. models/mutation.policy.appTenantRestriction.moveRule.json +27 -27
  81. models/mutation.policy.appTenantRestriction.moveSection.json +4 -4
  82. models/mutation.policy.appTenantRestriction.publishPolicyRevision.json +33 -33
  83. models/mutation.policy.appTenantRestriction.removeRule.json +27 -27
  84. models/mutation.policy.appTenantRestriction.removeSection.json +4 -4
  85. models/mutation.policy.appTenantRestriction.updatePolicy.json +33 -33
  86. models/mutation.policy.appTenantRestriction.updateRule.json +33 -33
  87. models/mutation.policy.appTenantRestriction.updateSection.json +4 -4
  88. models/mutation.policy.dynamicIpAllocation.addRule.json +12 -12
  89. models/mutation.policy.dynamicIpAllocation.addSection.json +4 -4
  90. models/mutation.policy.dynamicIpAllocation.createPolicyRevision.json +18 -18
  91. models/mutation.policy.dynamicIpAllocation.discardPolicyRevision.json +18 -18
  92. models/mutation.policy.dynamicIpAllocation.moveRule.json +12 -12
  93. models/mutation.policy.dynamicIpAllocation.moveSection.json +4 -4
  94. models/mutation.policy.dynamicIpAllocation.publishPolicyRevision.json +18 -18
  95. models/mutation.policy.dynamicIpAllocation.removeRule.json +12 -12
  96. models/mutation.policy.dynamicIpAllocation.removeSection.json +4 -4
  97. models/mutation.policy.dynamicIpAllocation.updatePolicy.json +18 -18
  98. models/mutation.policy.dynamicIpAllocation.updateRule.json +12 -12
  99. models/mutation.policy.dynamicIpAllocation.updateSection.json +4 -4
  100. models/mutation.policy.internetFirewall.addRule.json +141 -141
  101. models/mutation.policy.internetFirewall.addSection.json +4 -4
  102. models/mutation.policy.internetFirewall.createPolicyRevision.json +102 -102
  103. models/mutation.policy.internetFirewall.discardPolicyRevision.json +102 -102
  104. models/mutation.policy.internetFirewall.moveRule.json +96 -96
  105. models/mutation.policy.internetFirewall.moveSection.json +4 -4
  106. models/mutation.policy.internetFirewall.publishPolicyRevision.json +102 -102
  107. models/mutation.policy.internetFirewall.removeRule.json +96 -96
  108. models/mutation.policy.internetFirewall.removeSection.json +4 -4
  109. models/mutation.policy.internetFirewall.updatePolicy.json +102 -102
  110. models/mutation.policy.internetFirewall.updateRule.json +141 -141
  111. models/mutation.policy.internetFirewall.updateSection.json +4 -4
  112. models/mutation.policy.remotePortFwd.addRule.json +21 -21
  113. models/mutation.policy.remotePortFwd.addSection.json +4 -4
  114. models/mutation.policy.remotePortFwd.createPolicyRevision.json +24 -24
  115. models/mutation.policy.remotePortFwd.discardPolicyRevision.json +24 -24
  116. models/mutation.policy.remotePortFwd.moveRule.json +18 -18
  117. models/mutation.policy.remotePortFwd.moveSection.json +4 -4
  118. models/mutation.policy.remotePortFwd.publishPolicyRevision.json +24 -24
  119. models/mutation.policy.remotePortFwd.removeRule.json +18 -18
  120. models/mutation.policy.remotePortFwd.removeSection.json +4 -4
  121. models/mutation.policy.remotePortFwd.updatePolicy.json +24 -24
  122. models/mutation.policy.remotePortFwd.updateRule.json +21 -21
  123. models/mutation.policy.remotePortFwd.updateSection.json +4 -4
  124. models/mutation.policy.socketLan.addRule.json +97 -97
  125. models/mutation.policy.socketLan.addSection.json +4 -4
  126. models/mutation.policy.socketLan.createPolicyRevision.json +91 -91
  127. models/mutation.policy.socketLan.discardPolicyRevision.json +91 -91
  128. models/mutation.policy.socketLan.moveRule.json +85 -85
  129. models/mutation.policy.socketLan.moveSection.json +4 -4
  130. models/mutation.policy.socketLan.publishPolicyRevision.json +91 -91
  131. models/mutation.policy.socketLan.removeRule.json +85 -85
  132. models/mutation.policy.socketLan.removeSection.json +4 -4
  133. models/mutation.policy.socketLan.updatePolicy.json +91 -91
  134. models/mutation.policy.socketLan.updateRule.json +97 -97
  135. models/mutation.policy.socketLan.updateSection.json +4 -4
  136. models/mutation.policy.terminalServer.addRule.json +7 -7
  137. models/mutation.policy.terminalServer.addSection.json +4 -4
  138. models/mutation.policy.terminalServer.createPolicyRevision.json +13 -13
  139. models/mutation.policy.terminalServer.discardPolicyRevision.json +13 -13
  140. models/mutation.policy.terminalServer.moveRule.json +7 -7
  141. models/mutation.policy.terminalServer.moveSection.json +4 -4
  142. models/mutation.policy.terminalServer.publishPolicyRevision.json +13 -13
  143. models/mutation.policy.terminalServer.removeRule.json +7 -7
  144. models/mutation.policy.terminalServer.removeSection.json +4 -4
  145. models/mutation.policy.terminalServer.updatePolicy.json +13 -13
  146. models/mutation.policy.terminalServer.updateRule.json +7 -7
  147. models/mutation.policy.terminalServer.updateSection.json +4 -4
  148. models/mutation.policy.wanFirewall.addRule.json +157 -157
  149. models/mutation.policy.wanFirewall.addSection.json +4 -4
  150. models/mutation.policy.wanFirewall.createPolicyRevision.json +121 -121
  151. models/mutation.policy.wanFirewall.discardPolicyRevision.json +121 -121
  152. models/mutation.policy.wanFirewall.moveRule.json +115 -115
  153. models/mutation.policy.wanFirewall.moveSection.json +4 -4
  154. models/mutation.policy.wanFirewall.publishPolicyRevision.json +121 -121
  155. models/mutation.policy.wanFirewall.removeRule.json +115 -115
  156. models/mutation.policy.wanFirewall.removeSection.json +4 -4
  157. models/mutation.policy.wanFirewall.updatePolicy.json +121 -121
  158. models/mutation.policy.wanFirewall.updateRule.json +157 -157
  159. models/mutation.policy.wanFirewall.updateSection.json +4 -4
  160. models/mutation.policy.wanNetwork.addRule.json +103 -103
  161. models/mutation.policy.wanNetwork.addSection.json +4 -4
  162. models/mutation.policy.wanNetwork.createPolicyRevision.json +97 -97
  163. models/mutation.policy.wanNetwork.discardPolicyRevision.json +97 -97
  164. models/mutation.policy.wanNetwork.moveRule.json +91 -91
  165. models/mutation.policy.wanNetwork.moveSection.json +4 -4
  166. models/mutation.policy.wanNetwork.publishPolicyRevision.json +97 -97
  167. models/mutation.policy.wanNetwork.removeRule.json +91 -91
  168. models/mutation.policy.wanNetwork.removeSection.json +4 -4
  169. models/mutation.policy.wanNetwork.updatePolicy.json +97 -97
  170. models/mutation.policy.wanNetwork.updateRule.json +103 -103
  171. models/mutation.policy.wanNetwork.updateSection.json +4 -4
  172. models/mutation.site.addBgpPeer.json +10 -10
  173. models/mutation.site.addIpsecIkeV2SiteTunnels.json +2 -2
  174. models/mutation.site.addSocketAddOnCard.json +2 -2
  175. models/mutation.site.assignSiteBwLicense.json +12879 -0
  176. models/mutation.site.removeBgpPeer.json +10 -10
  177. models/mutation.site.removeIpsecIkeV2SiteTunnels.json +2 -2
  178. models/mutation.site.removeSecondaryAwsVSocket.json +375 -0
  179. models/mutation.site.removeSecondaryAzureVSocket.json +354 -0
  180. models/mutation.site.removeSiteBwLicense.json +12822 -0
  181. models/mutation.site.removeSocketAddOnCard.json +2 -2
  182. models/mutation.site.replaceSiteBwLicense.json +12939 -0
  183. models/mutation.site.startSiteUpgrade.json +36 -15
  184. models/mutation.site.updateBgpPeer.json +10 -10
  185. models/mutation.site.updateIpsecIkeV2SiteTunnels.json +2 -2
  186. models/mutation.site.updateSecondaryAwsVSocket.json +643 -0
  187. models/mutation.site.updateSecondaryAzureVSocket.json +565 -0
  188. models/mutation.site.updateSiteBwLicense.json +12882 -0
  189. models/mutation.site.updateSiteGeneralDetails.json +724 -1
  190. models/mutation.sites.addBgpPeer.json +10 -10
  191. models/mutation.sites.addIpsecIkeV2SiteTunnels.json +2 -2
  192. models/mutation.sites.addSocketAddOnCard.json +2 -2
  193. models/mutation.sites.assignSiteBwLicense.json +12879 -0
  194. models/mutation.sites.removeBgpPeer.json +10 -10
  195. models/mutation.sites.removeIpsecIkeV2SiteTunnels.json +2 -2
  196. models/mutation.sites.removeSecondaryAwsVSocket.json +375 -0
  197. models/mutation.sites.removeSecondaryAzureVSocket.json +354 -0
  198. models/mutation.sites.removeSiteBwLicense.json +12822 -0
  199. models/mutation.sites.removeSocketAddOnCard.json +2 -2
  200. models/mutation.sites.replaceSiteBwLicense.json +12939 -0
  201. models/mutation.sites.startSiteUpgrade.json +36 -15
  202. models/mutation.sites.updateBgpPeer.json +10 -10
  203. models/mutation.sites.updateIpsecIkeV2SiteTunnels.json +2 -2
  204. models/mutation.sites.updateSecondaryAwsVSocket.json +643 -0
  205. models/mutation.sites.updateSecondaryAzureVSocket.json +565 -0
  206. models/mutation.sites.updateSiteBwLicense.json +12882 -0
  207. models/mutation.sites.updateSiteGeneralDetails.json +724 -1
  208. models/mutation.xdr.addStoryComment.json +1 -1
  209. models/mutation.xdr.analystFeedback.json +84 -84
  210. models/mutation.xdr.deleteStoryComment.json +1 -1
  211. models/query.accountManagement.json +97 -0
  212. models/query.accountMetrics.json +45 -45
  213. models/query.accountSnapshot.json +30 -30
  214. models/query.admin.json +6 -6
  215. models/query.admins.json +13 -13
  216. models/query.appStats.json +915 -867
  217. models/query.appStatsTimeSeries.json +692 -656
  218. models/query.auditFeed.json +6 -6
  219. models/query.catalogs.json +52 -52
  220. models/query.container.json +16 -16
  221. models/query.devices.json +20 -93
  222. models/query.entityLookup.json +2 -2
  223. models/query.events.json +288 -384
  224. models/query.eventsFeed.json +73 -97
  225. models/query.eventsTimeSeries.json +219 -291
  226. models/query.groups.group.members.json +3058 -0
  227. models/query.groups.groupList.json +6474 -0
  228. models/query.groups.whereUsed.json +697 -0
  229. models/query.hardware.json +27 -7
  230. models/query.hardwareManagement.json +8 -8
  231. models/query.licensing.json +3487 -1324
  232. models/query.policy.appTenantRestriction.policy.json +32 -32
  233. models/query.policy.dynamicIpAllocation.policy.json +18 -18
  234. models/query.policy.internetFirewall.policy.json +93 -93
  235. models/query.policy.remotePortFwd.policy.json +23 -23
  236. models/query.policy.socketLan.policy.json +88 -88
  237. models/query.policy.terminalServer.policy.json +13 -13
  238. models/query.policy.wanFirewall.policy.json +111 -111
  239. models/query.policy.wanNetwork.policy.json +97 -97
  240. models/query.popLocations.json +2878 -0
  241. models/query.sandbox.json +5 -5
  242. models/query.site.bgpPeer.json +4 -4
  243. models/query.site.bgpPeerList.json +10 -10
  244. models/query.site.secondaryAwsVSocket.json +340 -0
  245. models/query.site.secondaryAzureVSocket.json +319 -0
  246. models/query.site.siteBgpStatus.json +2 -2
  247. models/query.socketPortMetrics.json +2410 -0
  248. models/query.socketPortMetricsTimeSeries.json +2361 -0
  249. models/query.xdr.stories.json +104 -104
  250. models/query.xdr.story.json +93 -93
  251. schema/catolib.py +43 -16
  252. build/lib/catocli/Utils/clidriver.py +0 -268
  253. build/lib/catocli/Utils/profile_manager.py +0 -188
  254. build/lib/catocli/Utils/version_checker.py +0 -192
  255. build/lib/catocli/__init__.py +0 -2
  256. build/lib/catocli/__main__.py +0 -12
  257. build/lib/catocli/parsers/configure/__init__.py +0 -115
  258. build/lib/catocli/parsers/configure/configure.py +0 -307
  259. build/lib/catocli/parsers/custom/__init__.py +0 -57
  260. build/lib/catocli/parsers/custom/customLib.py +0 -561
  261. build/lib/catocli/parsers/custom/export_rules/__init__.py +0 -42
  262. build/lib/catocli/parsers/custom/export_rules/export_rules.py +0 -234
  263. build/lib/catocli/parsers/custom/export_sites/__init__.py +0 -21
  264. build/lib/catocli/parsers/custom/export_sites/export_sites.py +0 -372
  265. build/lib/catocli/parsers/custom/import_rules_to_tf/__init__.py +0 -58
  266. build/lib/catocli/parsers/custom/import_rules_to_tf/import_rules_to_tf.py +0 -451
  267. build/lib/catocli/parsers/custom/import_sites_to_tf/__init__.py +0 -45
  268. build/lib/catocli/parsers/custom/import_sites_to_tf/import_sites_to_tf.py +0 -891
  269. build/lib/catocli/parsers/mutation_accountManagement/__init__.py +0 -48
  270. build/lib/catocli/parsers/mutation_admin/__init__.py +0 -48
  271. build/lib/catocli/parsers/mutation_container/__init__.py +0 -138
  272. build/lib/catocli/parsers/mutation_hardware/__init__.py +0 -22
  273. build/lib/catocli/parsers/mutation_policy/__init__.py +0 -1305
  274. build/lib/catocli/parsers/mutation_sandbox/__init__.py +0 -35
  275. build/lib/catocli/parsers/mutation_site/__init__.py +0 -373
  276. build/lib/catocli/parsers/mutation_sites/__init__.py +0 -373
  277. build/lib/catocli/parsers/mutation_xdr/__init__.py +0 -48
  278. build/lib/catocli/parsers/parserApiClient.py +0 -513
  279. build/lib/catocli/parsers/query_accountBySubdomain/__init__.py +0 -16
  280. build/lib/catocli/parsers/query_accountManagement/__init__.py +0 -16
  281. build/lib/catocli/parsers/query_accountMetrics/__init__.py +0 -16
  282. build/lib/catocli/parsers/query_accountRoles/__init__.py +0 -16
  283. build/lib/catocli/parsers/query_accountSnapshot/__init__.py +0 -16
  284. build/lib/catocli/parsers/query_admin/__init__.py +0 -16
  285. build/lib/catocli/parsers/query_admins/__init__.py +0 -16
  286. build/lib/catocli/parsers/query_appStats/__init__.py +0 -16
  287. build/lib/catocli/parsers/query_appStatsTimeSeries/__init__.py +0 -16
  288. build/lib/catocli/parsers/query_auditFeed/__init__.py +0 -16
  289. build/lib/catocli/parsers/query_catalogs/__init__.py +0 -16
  290. build/lib/catocli/parsers/query_container/__init__.py +0 -16
  291. build/lib/catocli/parsers/query_devices/__init__.py +0 -16
  292. build/lib/catocli/parsers/query_entityLookup/__init__.py +0 -16
  293. build/lib/catocli/parsers/query_events/__init__.py +0 -16
  294. build/lib/catocli/parsers/query_eventsFeed/__init__.py +0 -16
  295. build/lib/catocli/parsers/query_eventsTimeSeries/__init__.py +0 -16
  296. build/lib/catocli/parsers/query_hardware/__init__.py +0 -16
  297. build/lib/catocli/parsers/query_hardwareManagement/__init__.py +0 -16
  298. build/lib/catocli/parsers/query_licensing/__init__.py +0 -16
  299. build/lib/catocli/parsers/query_policy/__init__.py +0 -161
  300. build/lib/catocli/parsers/query_sandbox/__init__.py +0 -16
  301. build/lib/catocli/parsers/query_site/__init__.py +0 -100
  302. build/lib/catocli/parsers/query_siteLocation/__init__.py +0 -13
  303. build/lib/catocli/parsers/query_subDomains/__init__.py +0 -16
  304. build/lib/catocli/parsers/query_xdr/__init__.py +0 -35
  305. build/lib/catocli/parsers/raw/__init__.py +0 -12
  306. build/lib/graphql_client/__init__.py +0 -11
  307. build/lib/graphql_client/api/__init__.py +0 -3
  308. build/lib/graphql_client/api/call_api.py +0 -84
  309. build/lib/graphql_client/api_client.py +0 -192
  310. build/lib/graphql_client/api_client_types.py +0 -409
  311. build/lib/graphql_client/configuration.py +0 -232
  312. build/lib/graphql_client/models/__init__.py +0 -13
  313. build/lib/graphql_client/models/no_schema.py +0 -71
  314. build/lib/schema/catolib.py +0 -1141
  315. build/lib/schema/importSchema.py +0 -60
  316. build/lib/schema/remove_policyid.py +0 -89
  317. build/lib/schema/remove_policyid_mutations.py +0 -89
  318. build/lib/scripts/catolib.py +0 -62
  319. build/lib/scripts/export_if_rules_to_json.py +0 -188
  320. build/lib/scripts/export_wf_rules_to_json.py +0 -111
  321. build/lib/scripts/import_wf_rules_to_tfstate.py +0 -331
  322. build/lib/vendor/certifi/__init__.py +0 -4
  323. build/lib/vendor/certifi/__main__.py +0 -12
  324. build/lib/vendor/certifi/core.py +0 -114
  325. build/lib/vendor/certifi/py.typed +0 -0
  326. build/lib/vendor/six.py +0 -998
  327. build/lib/vendor/urllib3/__init__.py +0 -211
  328. build/lib/vendor/urllib3/_base_connection.py +0 -172
  329. build/lib/vendor/urllib3/_collections.py +0 -483
  330. build/lib/vendor/urllib3/_request_methods.py +0 -278
  331. build/lib/vendor/urllib3/_version.py +0 -16
  332. build/lib/vendor/urllib3/connection.py +0 -1033
  333. build/lib/vendor/urllib3/connectionpool.py +0 -1182
  334. build/lib/vendor/urllib3/contrib/__init__.py +0 -0
  335. build/lib/vendor/urllib3/contrib/emscripten/__init__.py +0 -18
  336. build/lib/vendor/urllib3/contrib/emscripten/connection.py +0 -254
  337. build/lib/vendor/urllib3/contrib/emscripten/fetch.py +0 -418
  338. build/lib/vendor/urllib3/contrib/emscripten/request.py +0 -22
  339. build/lib/vendor/urllib3/contrib/emscripten/response.py +0 -285
  340. build/lib/vendor/urllib3/contrib/pyopenssl.py +0 -552
  341. build/lib/vendor/urllib3/contrib/socks.py +0 -228
  342. build/lib/vendor/urllib3/exceptions.py +0 -321
  343. build/lib/vendor/urllib3/fields.py +0 -341
  344. build/lib/vendor/urllib3/filepost.py +0 -89
  345. build/lib/vendor/urllib3/http2/__init__.py +0 -53
  346. build/lib/vendor/urllib3/http2/connection.py +0 -356
  347. build/lib/vendor/urllib3/http2/probe.py +0 -87
  348. build/lib/vendor/urllib3/poolmanager.py +0 -637
  349. build/lib/vendor/urllib3/py.typed +0 -2
  350. build/lib/vendor/urllib3/response.py +0 -1265
  351. build/lib/vendor/urllib3/util/__init__.py +0 -42
  352. build/lib/vendor/urllib3/util/connection.py +0 -137
  353. build/lib/vendor/urllib3/util/proxy.py +0 -43
  354. build/lib/vendor/urllib3/util/request.py +0 -256
  355. build/lib/vendor/urllib3/util/response.py +0 -101
  356. build/lib/vendor/urllib3/util/retry.py +0 -533
  357. build/lib/vendor/urllib3/util/ssl_.py +0 -513
  358. build/lib/vendor/urllib3/util/ssl_match_hostname.py +0 -159
  359. build/lib/vendor/urllib3/util/ssltransport.py +0 -276
  360. build/lib/vendor/urllib3/util/timeout.py +0 -275
  361. build/lib/vendor/urllib3/util/url.py +0 -471
  362. build/lib/vendor/urllib3/util/util.py +0 -42
  363. build/lib/vendor/urllib3/util/wait.py +0 -124
  364. {catocli-2.0.5.dist-info → catocli-2.1.1.dist-info}/entry_points.txt +0 -0
  365. {catocli-2.0.5.dist-info → catocli-2.1.1.dist-info/licenses}/LICENSE +0 -0
@@ -1,1141 +0,0 @@
1
- #!/usr/bin/python
2
- import datetime
3
- import json
4
- import ssl
5
- import sys
6
- import time
7
- import urllib.parse
8
- import urllib.request
9
- import logging
10
- from optparse import OptionParser
11
- import os
12
- import sys
13
- import copy
14
-
15
- api_call_count = 0
16
- start = datetime.datetime.now()
17
- catoApiIntrospection = {
18
- "enums": {},
19
- "scalars": {},
20
- "objects": {},
21
- "input_objects": {},
22
- "unions": {},
23
- "interfaces": {},
24
- "unknowns": {}
25
- }
26
- catoApiSchema = {
27
- "query": {},
28
- "mutation": {}
29
- }
30
-
31
- def initParser():
32
- if "CATO_TOKEN" not in os.environ:
33
- print("Missing authentication, please set the CATO_TOKEN environment variable with your api key.")
34
- exit()
35
- if "CATO_ACCOUNT_ID" not in os.environ:
36
- print("Missing authentication, please set the CATO_ACCOUNT_ID environment variable with your api key.")
37
- exit()
38
-
39
- # Process options
40
- parser = OptionParser()
41
- parser.add_option("-P", dest="prettify", action="store_true", help="Prettify output")
42
- parser.add_option("-p", dest="print_entities", action="store_true", help="Print entity records")
43
- parser.add_option("-v", dest="verbose", action="store_true", help="Print debug info")
44
- (options, args) = parser.parse_args()
45
- options.api_key = os.getenv("CATO_TOKEN")
46
- if options.verbose:
47
- logging.getLogger().setLevel(logging.DEBUG)
48
- else:
49
- logging.getLogger().setLevel(logging.INFO)
50
- return options
51
-
52
- def loadJSON(file):
53
- CONFIG = {}
54
- try:
55
- with open(file, 'r') as data:
56
- CONFIG = json.load(data)
57
- logging.warning("Loaded "+file+" data")
58
- return CONFIG
59
- except:
60
- logging.warning("File \""+file+"\" not found.")
61
- exit()
62
-
63
- def writeFile(fileName, data):
64
- open(fileName, 'w+').close()
65
- file=open(fileName,"w+")
66
- file.write(data)
67
-
68
- def openFile(fileName, readMode="rt"):
69
- try:
70
- with open(fileName, readMode) as f:
71
- fileTxt = f.read()
72
- f.closed
73
- return fileTxt
74
- except:
75
- print('[ERROR] File path "'+fileName+'" in csv not found, or script unable to read.')
76
- exit()
77
-
78
- ############ parsing schema ############
79
-
80
- def parseSchema(schema):
81
- # Load settings to get childOperationParent and childOperationObjects configuration
82
- settings = loadJSON("../settings.json")
83
- childOperationParent = settings.get("childOperationParent", {})
84
- childOperationObjects = settings.get("childOperationObjects", {})
85
-
86
- mutationOperationsTMP = {}
87
- queryOperationsTMP = {}
88
- for i, type in enumerate(schema["data"]["__schema"]["types"]):
89
- if type["kind"] == "ENUM":
90
- catoApiIntrospection["enums"][type["name"]] = copy.deepcopy(type)
91
- elif type["kind"] == "SCALAR":
92
- catoApiIntrospection["scalars"][type["name"]] = copy.deepcopy(type)
93
- elif type["kind"] == "INPUT_OBJECT":
94
- catoApiIntrospection["input_objects"][type["name"]] = copy.deepcopy(type)
95
- elif type["kind"] == "INTERFACE":
96
- catoApiIntrospection["interfaces"][type["name"]] = copy.deepcopy(type)
97
- elif type["kind"] == "UNION":
98
- catoApiIntrospection["unions"][type["name"]] = copy.deepcopy(type)
99
- elif type["kind"] == "OBJECT":
100
- if type["name"] == "Query":
101
- for field in type["fields"]:
102
- if field["name"] in childOperationParent:
103
- queryOperationsTMP[field["name"]] = copy.deepcopy(field)
104
- else:
105
- catoApiSchema["query"]["query."+field["name"]] = copy.deepcopy(field)
106
- # catoParserMapping["query"][field["name"]]
107
- elif type["name"] == "Mutation":
108
- for field in type["fields"]:
109
- mutationOperationsTMP[field["name"]] = copy.deepcopy(field)
110
- else:
111
- catoApiIntrospection["objects"][type["name"]] = copy.deepcopy(type)
112
-
113
- for queryType in queryOperationsTMP:
114
- parentQueryOperationType = copy.deepcopy(queryOperationsTMP[queryType])
115
- getChildOperations("query", parentQueryOperationType, parentQueryOperationType, "query." + queryType, childOperationObjects)
116
-
117
- for mutationType in mutationOperationsTMP:
118
- parentMutationOperationType = copy.deepcopy(mutationOperationsTMP[mutationType])
119
- getChildOperations("mutation", parentMutationOperationType, parentMutationOperationType, "mutation." + mutationType, childOperationObjects)
120
-
121
- for operationType in catoApiSchema:
122
- for operationName in catoApiSchema[operationType]:
123
- # if operationName=="query.xdr.stories":
124
- childOperations = catoApiSchema[operationType][operationName]["childOperations"].keys() if "childOperations" in catoApiSchema[operationType][operationName] and catoApiSchema[operationType][operationName]!=None else []
125
- parsedOperation = parseOperation(catoApiSchema[operationType][operationName],childOperations)
126
- parsedOperation = getOperationArgs(parsedOperation["type"]["definition"],parsedOperation)
127
- parsedOperation["path"] = operationName
128
- for argName in parsedOperation["args"]:
129
- arg = parsedOperation["args"][argName]
130
- parsedOperation["operationArgs"][arg["varName"]] = arg
131
- parsedOperation["variablesPayload"] = generateExampleVariables(parsedOperation)
132
- writeFile("../models/"+operationName+".json",json.dumps(parsedOperation, indent=4, sort_keys=True))
133
- writeFile("../queryPayloads/"+operationName+".json",json.dumps(generateGraphqlPayload(parsedOperation["variablesPayload"],parsedOperation,operationName),indent=4,sort_keys=True))
134
- payload = generateGraphqlPayload(parsedOperation["variablesPayload"],parsedOperation,operationName)
135
- writeFile("../queryPayloads/"+operationName+".txt",payload["query"])
136
-
137
- def getChildOperations(operationType, curType, parentType, parentPath, childOperationObjects):
138
- # Parse fields for nested args to map out all child operations
139
- # This will separate fields like stories and story for query.xdr,
140
- # and all fields which are actually sub operations from mutation.internetFirewall, etc
141
- if "childOperations" not in parentType:
142
- parentType["childOperations"] = {}
143
- curOfType = None
144
- if "kind" in curType:
145
- curOfType = copy.deepcopy(catoApiIntrospection[curType["kind"].lower() + "s"][curType["name"]])
146
- elif "type" in curType and curType["type"]["ofType"]==None:
147
- curOfType = copy.deepcopy(catoApiIntrospection[curType["type"]["kind"].lower() + "s"][curType["type"]["name"]])
148
- elif "type" in curType and curType["type"]["ofType"]["ofType"]==None:
149
- curOfType = copy.deepcopy(catoApiIntrospection[curType["type"]["ofType"]["kind"].lower() + "s"][curType["type"]["ofType"]["name"]])
150
- elif "type" in curType and curType["type"]["ofType"]["ofType"]["ofType"]==None:
151
- curOfType = copy.deepcopy(catoApiIntrospection[curType["type"]["ofType"]["ofType"]["kind"].lower() + "s"][curType["type"]["ofType"]["ofType"]["name"]])
152
- elif "type" in curType and curType["type"]["ofType"]["ofType"]["ofType"]["ofType"]==None:
153
- curOfType = copy.deepcopy(catoApiIntrospection[curType["type"]["ofType"]["ofType"]["ofType"]["kind"].lower() + "s"][curType["type"]["ofType"]["ofType"]["ofType"]["name"]])
154
- else:
155
- curOfType = copy.deepcopy(catoApiIntrospection[curType["type"]["ofType"]["ofType"]["ofType"]["ofType"]["kind"].lower() + "s"][curType["type"]["ofType"]["ofType"]["ofType"]["ofType"]["name"]])
156
- hasChildren = False
157
-
158
- if "fields" in curOfType and curOfType["fields"] != None:
159
- parentFields = []
160
- for field in curOfType["fields"]:
161
- curFieldObject = copy.deepcopy(field)
162
- if (("args" in curFieldObject and len(curFieldObject["args"])>0) or
163
- (curFieldObject["name"] in childOperationObjects) or
164
- (curOfType["name"] in childOperationObjects)):
165
- hasChildren = True
166
- curParentType = copy.deepcopy(parentType)
167
- curFieldObject["args"] = getNestedArgDefinitions(curFieldObject["args"], curFieldObject["name"],None,None)
168
- curParentType["childOperations"][curFieldObject["name"]] = curFieldObject
169
- getChildOperations(operationType, curFieldObject, curParentType, parentPath + "." + curFieldObject["name"], childOperationObjects)
170
- if not hasChildren:
171
- catoApiSchema[operationType][parentPath] = parentType
172
-
173
- def getNestedArgDefinitions(argsAry, parentParamPath, childOperations, parentFields):
174
- newArgsList = {}
175
- for arg in argsAry:
176
- curParamPath = renderCamelCase(arg["name"]) if (parentParamPath == None or parentParamPath == "") else parentParamPath.replace("___",".") + "." + renderCamelCase(arg["name"])
177
- if "path" in arg and '.' not in arg["path"]:
178
- arg["child"] = True
179
- arg["parent"] = arg["path"]
180
- arg["type"] = getOfType(arg["type"], { "non_null": False, "kind": [], "name": None }, curParamPath, childOperations, parentFields)
181
- arg["path"] = curParamPath
182
- arg["id_str"] = curParamPath.replace(".","___")
183
- if isinstance(arg["type"]["kind"], list):
184
- arg["required"] = True if arg["type"]["kind"][0] == "NON_NULL" else False
185
- else:
186
- arg["required"] = True if arg["type"]["kind"] == "NON_NULL" else False
187
- required1 = "!" if arg["required"] else ""
188
- required2 = "!" if "NON_NULL" in arg["type"]["kind"][1:] else ""
189
- if "SCALAR" in arg["type"]["kind"] or "ENUM" in arg["type"]["kind"]:
190
- arg["varName"] = renderCamelCase(arg["name"])
191
- # arg["id_str"] = arg["varName"]
192
- else:
193
- arg["varName"] = renderCamelCase(arg["type"]["name"])
194
- arg["responseStr"] = arg["name"] + ":$" + arg["varName"] + " "
195
- if "LIST" in arg["type"]["kind"]:
196
- arg["requestStr"] = "$" + arg["varName"] + ":" + "[" + arg["type"]["name"] + required2 + "]" + required1 + " "
197
- else:
198
- arg["requestStr"] = "$" + arg["varName"] + ":" + arg["type"]["name"] + required1 + " "
199
- newArgsList[arg["id_str"]] = arg
200
- # print("getNestedArgDefinitions()",newArgsList.keys())
201
- return newArgsList
202
-
203
- def getOfType(curType, ofType, parentParamPath, childOperations, parentFields):
204
- ofType["kind"].append(copy.deepcopy(curType["kind"]))
205
- curParamPath = "" if (parentParamPath == None) else parentParamPath + "___"
206
- if curType["ofType"] != None:
207
- ofType = getOfType(copy.deepcopy(curType["ofType"]), ofType, parentParamPath,childOperations,parentFields)
208
- else:
209
- ofType["name"] = curType["name"]
210
- parentFields = []
211
- if "definition" in ofType and "fields" in ofType["definition"] and ofType["definition"]["fields"]!=None:
212
- for fieldName in ofType["definition"]["fields"]:
213
- field = ofType["definition"]["fields"][fieldName]
214
- parentFields.append(field["name"])
215
- if "INPUT_OBJECT" in ofType["kind"]:
216
- ofType["indexType"] = "input_object"
217
- ofType["definition"] = copy.deepcopy(catoApiIntrospection["input_objects"][ofType["name"]])
218
- if ofType["definition"]["inputFields"] != None:
219
- ofType["definition"]["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["inputFields"]), curParamPath, childOperations, parentFields)
220
- elif "UNION" in ofType["kind"]:
221
- ofType["indexType"] = "interface"
222
- ofType["definition"] = copy.deepcopy(catoApiIntrospection["unions"][ofType["name"]])
223
- if ofType["definition"]["possibleTypes"] != None:
224
- ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath,childOperations, parentFields)
225
- # strip out each nested interface attribute from parent oftype fields,
226
- # this is to prevent duplicate fields causing the query to fail
227
- for interfaceName in ofType["definition"]["possibleTypes"]:
228
- possibleType = ofType["definition"]["possibleTypes"][interfaceName]
229
- if ofType["definition"]["fields"]!=None:
230
- for fieldName in ofType["definition"]["fields"]:
231
- field = ofType["definition"]["fields"][fieldName]
232
- nestedFieldPath = parentParamPath + interfaceName + "___" + field["name"]
233
- # aliasLogic
234
- # if field["name"] in parentFields:
235
- # field["alias"] = renderCamelCase(interfaceName+"."+field["name"])+": "+field["name"]
236
- # if "SCALAR" in field["type"]["kind"] or "ENUM" in field["type"]["kind"]:
237
- # possibleType["fields"][nestedFieldPath]["alias"] = renderCamelCase(interfaceName+"."+field["name"])+": "+field["name"]
238
- # else:
239
- # possibleType["fields"][nestedFieldPath]["alias"] = renderCamelCase(field["type"]["name"])+": "+field["name"]
240
- ofType["definition"]["possibleTypes"][interfaceName] = copy.deepcopy(possibleType)
241
- elif "OBJECT" in ofType["kind"]:
242
- ofType["indexType"] = "object"
243
- ofType["definition"] = copy.deepcopy(catoApiIntrospection["objects"][ofType["name"]])
244
- if ofType["definition"]["fields"] != None and childOperations!=None:
245
- ofType["definition"]["fields"] = checkForChildOperation(copy.deepcopy(ofType["definition"]["fields"]),childOperations)
246
- ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath,childOperations, parentFields)
247
- if ofType["definition"]["interfaces"] != None:
248
- ofType["definition"]["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["interfaces"]), curParamPath,childOperations, parentFields)
249
- elif "INTERFACE" in ofType["kind"]:
250
- ofType["indexType"] = "interface"
251
- ofType["definition"] = copy.deepcopy(catoApiIntrospection["interfaces"][ofType["name"]])
252
- if ofType["definition"]["fields"] != None:
253
- ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields)
254
- if ofType["definition"]["possibleTypes"] != None:
255
- ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields)
256
- for interfaceName in ofType["definition"]["possibleTypes"]:
257
- possibleType = copy.deepcopy(ofType["definition"]["possibleTypes"][interfaceName])
258
- for fieldName in ofType["definition"]["fields"]:
259
- field = ofType["definition"]["fields"][fieldName]
260
- nestedFieldPath = parentParamPath + interfaceName + "." + field["name"]
261
- nestedFieldPath = nestedFieldPath.replace(".","___")
262
- if "args" in field and len(field["args"])>0:
263
- field["args"] = getNestedArgDefinitions(copy.deepcopy(field["args"]), nestedFieldPath, curParamPath, parentFields)
264
- # aliasLogic MUST
265
- # CatoEndpointUser
266
- if field["name"] in possibleType["fields"] and possibleType["fields"][field["name"]] != None:
267
- # del possibleType["fields"][field["name"]]
268
- if "SCALAR" in field["type"]["kind"] or "ENUM" in field["type"]["kind"]:
269
- possibleType["fields"][field["name"]]["alias"] = renderCamelCase(interfaceName+"."+field["name"])+": "+field["name"]
270
- else:
271
- possibleType["fields"][field["name"]]["alias"] = renderCamelCase(field["type"]["name"])+": "+field["name"]
272
- ofType["definition"]["possibleTypes"][interfaceName] = copy.deepcopy(possibleType)
273
- if ofType["definition"]["interfaces"] != None:
274
- ofType["definition"]["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["interfaces"]), curParamPath,childOperations, parentFields)
275
- elif "ENUM" in ofType["kind"]:
276
- ofType["indexType"] = "enum"
277
- ofType["definition"] = copy.deepcopy(catoApiIntrospection["enums"][ofType["name"]])
278
- return ofType
279
-
280
- def getNestedFieldDefinitions(fieldsAry, parentParamPath,childOperations, parentFields):
281
- newFieldsList = {}
282
- for field in fieldsAry:
283
- if isinstance(field,str):
284
- field = fieldsAry[field]
285
- curParamPath = field["name"] if (parentParamPath == None) else (parentParamPath.replace("___",".") + field["name"])
286
- # curParamPath = field["name"] if (parentParamPath == None) else (parentParamPath + "." + field["name"])
287
- field["type"] = getOfType(field["type"], { "non_null": False, "kind": [], "name": None }, curParamPath,childOperations, parentFields)
288
- field["path"] = curParamPath
289
- field["id_str"] = curParamPath.replace(".","___")
290
- if isinstance(field["type"]["kind"], list):
291
- field["required"] = True if field["type"]["kind"][0] == "NON_NULL" else False
292
- else:
293
- field["required"] = True if field["type"]["kind"] == "NON_NULL" else False
294
- required1 = "!" if field["required"] else ""
295
- required2 = "!" if field["type"]["kind"][1:] == "NON_NULL" else ""
296
- if "SCALAR" in field["type"]["kind"] or "ENUM" in field["type"]["kind"]:
297
- field["varName"] = renderCamelCase(field["name"])
298
- # field["id_str"] = field["varName"]
299
- else:
300
- field["varName"] = renderCamelCase(field["type"]["name"])
301
- field["responseStr"] = field["name"] + ":$" + field["varName"] + " "
302
- if "LIST" in field["type"]["kind"]:
303
- field["requestStr"] = "$" + field["varName"] + ":" + "[" + field["type"]["name"] + required2 + "]" + required1 + " "
304
- else:
305
- field["requestStr"] = "$" + field["varName"] + ":" + field["type"]["name"] + required1 + " "
306
- if "args" in field:
307
- field["args"] = getNestedArgDefinitions(field["args"], field["name"],childOperations, parentFields)
308
- ## aliasLogic must
309
- if parentFields!=None and field["name"] in parentFields and "SCALAR" not in field["type"]["kind"]:
310
- # if field["name"]=="records":
311
- # raise ValueError('A very specific bad thing happened.')
312
- # print(json.dumps(field,indent=2,sort_keys=True))
313
- # print(field["path"],parentFields)
314
- # field["alias"] = renderCamelCase(field["type"]["name"]+"."+field["name"])+": "+field["name"]
315
- field["alias"] = renderCamelCase(field["type"]["name"]+"."+field["name"])+": "+field["name"]
316
- if "records.fields" not in field["path"]:
317
- newFieldsList[field["name"]] = field
318
- # for (fieldPath in newFieldList) {
319
- # var field = newFieldList[fieldPath];
320
- # if (curOperationObj.fieldTypes && field.type.name != null) curOperationObj.fieldTypes[field.type.name] = true;
321
- # field.type = getOfType(field.type, { non_null: false, kind: [], name: null }, field.path);
322
- # }
323
- return newFieldsList
324
-
325
- def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath,childOperations, parentFields):
326
- curInterfaces = {}
327
- for possibleType in possibleTypesAry:
328
- if "OBJECT" in possibleType["kind"]:
329
- curInterfaces[possibleType["name"]] = copy.deepcopy(catoApiIntrospection["objects"][possibleType["name"]])
330
- # for curInterface in curInterfaces:
331
- # curParamPath = "" if parentParamPath == None else parentParamPath + curInterface["name"] + "___"
332
- for curInterfaceName in curInterfaces:
333
- curInterface = curInterfaces[curInterfaceName]
334
- curParamPath = "" if parentParamPath == None else parentParamPath + curInterface["name"] + "___"
335
- if "fields" in curInterface and curInterface["fields"] != None:
336
- curInterface["fields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["fields"]), curParamPath,childOperations, parentFields)
337
- if "inputFields" in curInterface and curInterface["inputFields"] != None:
338
- curInterface["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["inputFields"]), curParamPath,childOperations, parentFields)
339
- if "interfaces" in curInterface and curInterface["interfaces"] != None:
340
- curInterface["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["interfaces"]), curParamPath,childOperations, parentFields)
341
- if "possibleTypes" in curInterface and curInterface["possibleTypes"] != None:
342
- curInterface["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["possibleTypes"]), curParamPath,childOperations, parentFields)
343
- return curInterfaces
344
-
345
- def parseOperation(curOperation,childOperations):
346
- if "operationArgs" not in curOperation:
347
- curOperation["operationArgs"] = {}
348
- curOperation["fieldTypes"] = {}
349
- curOfType = getOfType(curOperation["type"], { "non_null": False, "kind": [], "name": None }, None,childOperations,None)
350
- curOperation["type"] = copy.deepcopy(curOfType)
351
- if curOfType["name"] in catoApiIntrospection["objects"]:
352
- curOperation["args"] = getNestedArgDefinitions(curOperation["args"], None,childOperations,None)
353
- curOperation["type"]["definition"] = copy.deepcopy(catoApiIntrospection["objects"][curOperation["type"]["name"]])
354
- if "fields" in curOperation["type"]["definition"] and curOperation["type"]["definition"]["fields"] != None:
355
- # aliasLogic
356
- # parentFields = []
357
- # for field in curOperation["type"]["definition"]["fields"]:
358
- # parentFields.append(field["name"])
359
- curOperation["type"]["definition"]["fields"] = checkForChildOperation(copy.deepcopy(curOperation["type"]["definition"]["fields"]),childOperations)
360
- curOperation["type"]["definition"]["fields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["fields"], None,childOperations,[]))
361
- if "inputFields" in curOperation["type"]["definition"] and curOperation["type"]["definition"]["inputFields"] != None:
362
- parentFields = curOperation["type"]["definition"]["inputFields"].keys()
363
- curOperation["type"]["definition"]["inputFields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["inputFields"], None,childOperations,parentFields))
364
- return curOperation
365
-
366
- def checkForChildOperation(fieldsAry,childOperations):
367
- newFieldList = {}
368
- subOperation = False
369
- for i, field in enumerate(fieldsAry):
370
- if field["name"] in childOperations:
371
- subOperation = field
372
- newFieldList[field["name"]] = copy.deepcopy(field)
373
- if subOperation != False:
374
- newFieldList = {}
375
- newFieldList[subOperation["name"]] = subOperation
376
- return newFieldList
377
-
378
- def getOperationArgs(curType,curOperation):
379
- if curType.get('fields'):
380
- for fieldName in curType["fields"]:
381
- field = curType["fields"][fieldName]
382
- ## aliasLogic
383
- if "type" in field and "definition" in field["type"]:
384
- curOperation["fieldTypes"][field["type"]["definition"]["name"]] = True
385
- curOperation = getOperationArgs(field["type"]["definition"],curOperation)
386
- if "args" in field:
387
- for argName in field["args"]:
388
- arg = field["args"][argName]
389
- curOperation["operationArgs"][arg["varName"]] = arg
390
- if "type" in arg and "definition" in arg["type"]:
391
- curOperation = getOperationArgs(arg["type"]["definition"],curOperation)
392
- if curType.get('inputFields'):
393
- for inputFieldName in curType["inputFields"]:
394
- inputField = curType["inputFields"][inputFieldName]
395
- if "type" in inputField and "definition" in inputField["type"]:
396
- curOperation["fieldTypes"][inputField["type"]["definition"]["name"]] = True
397
- curOperation = getOperationArgs(inputField["type"]["definition"],curOperation)
398
- if "args" in inputField:
399
- for argName in inputField["args"]:
400
- arg = inputField["args"][argName]
401
- curOperation["operationArgs"][arg["varName"]] = arg
402
- if "type" in arg and "definition" in arg["type"]:
403
- curOperation = getOperationArgs(arg["type"]["definition"],curOperation)
404
- if curType.get('interfaces'):
405
- for interface in curType["interfaces"]:
406
- if "type" in interface and "definition" in interface["type"]:
407
- curOperation["fieldTypes"][interface["type"]["definition"]["name"]] = True
408
- curOperation = getOperationArgs(interface["type"]["definition"],curOperation)
409
- if "args" in interface:
410
- for argName in interface["args"]:
411
- arg = interface["args"][argName]
412
- curOperation["operationArgs"][arg["varName"]] = arg
413
- if "type" in arg and "definition" in arg["type"]:
414
- curOperation = getOperationArgs(arg["type"]["definition"],curOperation)
415
- if curType.get('possibleTypes'):
416
- for possibleTypeName in curType["possibleTypes"]:
417
- possibleType = curType["possibleTypes"][possibleTypeName]
418
- curOperation = getOperationArgs(possibleType,curOperation)
419
- if possibleType.get('fields'):
420
- for fieldName in possibleType["fields"]:
421
- field = possibleType["fields"][fieldName]
422
- ## aliasLogic
423
- # if "type" in curOperation and "definition" in curOperation["type"] and "fields" in curOperation["type"]["definition"] and field["name"] in curOperation["type"]["definition"]["fields"]:
424
- # # if field["type"]["definition"]["fields"]==None or field["type"]["definition"]["inputFields"]:
425
- # # if "SCALAR" not in field["type"]["kind"] or "ENUM" not in field["type"]["kind"]:
426
- # field["alias"] = renderCamelCase(possibleTypeName+"."+field["name"])+": "+field["name"]
427
- if "args" in possibleType:
428
- for argName in possibleType["args"]:
429
- arg = possibleType["args"][argName]
430
- curOperation["operationArgs"][arg["varName"]] = arg
431
- if "type" in arg and "definition" in arg["type"]:
432
- curOperation = getOperationArgs(arg["type"]["definition"],curOperation)
433
- return curOperation
434
-
435
- def renderCamelCase(pathStr):
436
- str = ""
437
- pathAry = pathStr.split(".")
438
- for i, path in enumerate(pathAry):
439
- if i == 0:
440
- str += path[0].lower() + path[1:]
441
- else:
442
- str += path[0].upper() + path[1:]
443
- return str
444
-
445
- ## Functions to create sample nested variable objects for cli arguments ##
446
- def generateExampleVariables(operation):
447
- variablesObj = {}
448
- for argName in operation["operationArgs"]:
449
- arg = operation["operationArgs"][argName]
450
- if "SCALAR" in arg["type"]["kind"] or "ENUM" in arg["type"]["kind"]:
451
- variablesObj[arg["name"]] = renderInputFieldVal(arg)
452
- else:
453
- argTD = arg["type"]["definition"]
454
- variablesObj[arg["varName"]] = {}
455
- if "inputFields" in argTD and argTD["inputFields"] != None:
456
- for inputFieldName in argTD["inputFields"]:
457
- inputField = argTD["inputFields"][inputFieldName]
458
- variablesObj[arg["varName"]][inputField["varName"]] = parseNestedArgFields(inputField)
459
- if "fields" in argTD and argTD["fields"] != None:
460
- for fieldName in argTD["fields"]:
461
- field = argTD["fields"][fieldName]
462
- variablesObj[arg["varName"]][field["varName"]] = parseNestedArgFields(field)
463
- if "possibleTypes" in argTD and argTD["possibleTypes"] != None:
464
- for possibleTypeName in argTD["possibleTypes"]:
465
- possibleType = argTD["possibleTypes"][possibleTypeName]
466
- variablesObj[arg["varName"]][possibleType["varName"]] = parseNestedArgFields(possibleTypeName)
467
- if "accountID" in variablesObj:
468
- del variablesObj["accountID"]
469
- if "accountId" in variablesObj:
470
- del variablesObj["accountId"]
471
- return variablesObj
472
-
473
- def parseNestedArgFields(fieldObj):
474
- subVariableObj = {}
475
- if "SCALAR" in fieldObj["type"]["kind"] or "ENUM" in fieldObj["type"]["kind"]:
476
- subVariableObj[fieldObj["name"]] = renderInputFieldVal(fieldObj)
477
- else:
478
- fieldTD = fieldObj["type"]["definition"]
479
- if "inputFields" in fieldTD and fieldTD["inputFields"] != None:
480
- for inputFieldName in fieldTD["inputFields"]:
481
- inputField = fieldTD["inputFields"][inputFieldName]
482
- subVariableObj[inputField["name"]] = parseNestedArgFields(inputField)
483
- if "fields" in fieldTD and fieldTD["fields"] != None:
484
- for fieldName in fieldTD["fields"]:
485
- field = fieldTD["fields"][fieldName]
486
- subVariableObj[field["name"]] = parseNestedArgFields(field)
487
- if "possibleTypes" in fieldTD and fieldTD["possibleTypes"] != None:
488
- for possibleTypeName in fieldTD["possibleTypes"]:
489
- possibleType = fieldTD["possibleTypes"][possibleTypeName]
490
- subVariableObj[possibleType["name"]] = parseNestedArgFields(possibleTypeName)
491
- return subVariableObj
492
-
493
- def renderInputFieldVal(arg):
494
- value = "string"
495
- if "SCALAR" in arg["type"]["kind"]:
496
- if "LIST" in arg["type"]["kind"]:
497
- value = [arg["type"]["name"]]
498
- else:
499
- value = arg["type"]["name"]
500
- elif "ENUM" in arg["type"]["kind"]:
501
- value = "enum("+arg["type"]["name"]+")"
502
- # arg["type"]["definition"]["enumValues"][0]["name"]
503
- return value
504
-
505
- def writeCliDriver(catoApiSchema):
506
- parsersIndex = {}
507
- for operationType in catoApiSchema:
508
- for operation in catoApiSchema[operationType]:
509
- operationNameAry = operation.split(".")
510
- parsersIndex[operationNameAry[0]+"_"+operationNameAry[1]] = True
511
- parsers = list(parsersIndex.keys())
512
-
513
- cliDriverStr = """
514
- import os
515
- import argparse
516
- import json
517
- import catocli
518
- from graphql_client import Configuration
519
- from graphql_client.api_client import ApiException
520
- from ..parsers.parserApiClient import get_help
521
- from .profile_manager import get_profile_manager
522
- from .version_checker import check_for_updates, force_check_updates
523
- import traceback
524
- import sys
525
- sys.path.insert(0, 'vendor')
526
- import urllib3
527
- urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
528
- # Initialize profile manager
529
- profile_manager = get_profile_manager()
530
- CATO_DEBUG = bool(os.getenv("CATO_DEBUG", False))
531
- from ..parsers.raw import raw_parse
532
- from ..parsers.custom import custom_parse
533
- from ..parsers.query_siteLocation import query_siteLocation_parse
534
- """
535
- for parserName in parsers:
536
- cliDriverStr += "from ..parsers."+parserName+" import "+parserName+"_parse\n"
537
-
538
- cliDriverStr += """
539
- def show_version_info(args, configuration=None):
540
- print(f"catocli version {catocli.__version__}")
541
-
542
- if not args.current_only:
543
- if args.check_updates:
544
- # Force check for updates
545
- is_newer, latest_version, source = force_check_updates()
546
- else:
547
- # Regular check (uses cache)
548
- is_newer, latest_version, source = check_for_updates(show_if_available=False)
549
-
550
- if latest_version:
551
- if is_newer:
552
- print(f"Latest version: {latest_version} (from {source}) - UPDATE AVAILABLE!")
553
- print()
554
- print("To upgrade, run:")
555
- print("pip install --upgrade catocli")
556
- else:
557
- print(f"Latest version: {latest_version} (from {source}) - You are up to date!")
558
- else:
559
- print("Unable to check for updates (check your internet connection)")
560
- return [{"success": True, "current_version": catocli.__version__, "latest_version": latest_version if not args.current_only else None}]
561
-
562
- def get_configuration(skip_api_key=False):
563
- configuration = Configuration()
564
- configuration.verify_ssl = False
565
- configuration.debug = CATO_DEBUG
566
- configuration.version = "{}".format(catocli.__version__)
567
-
568
- # Try to migrate from environment variables first
569
- profile_manager.migrate_from_environment()
570
-
571
- # Get credentials from profile
572
- credentials = profile_manager.get_credentials()
573
- if not credentials:
574
- print("No Cato CLI profile configured.")
575
- print("Run 'catocli configure set' to set up your credentials.")
576
- exit(1)
577
-
578
- if not credentials.get('cato_token') or not credentials.get('account_id'):
579
- profile_name = profile_manager.get_current_profile()
580
- print(f"Profile '{profile_name}' is missing required credentials.")
581
- print(f"Run 'catocli configure set --profile {profile_name}' to update your credentials.")
582
- exit(1)
583
-
584
- # Only set API key if not using custom headers file
585
- if not skip_api_key:
586
- configuration.api_key["x-api-key"] = credentials['cato_token']
587
- configuration.host = credentials['endpoint']
588
- configuration.accountID = credentials['account_id']
589
-
590
- return configuration
591
-
592
- defaultReadmeStr = \"""
593
- The Cato CLI is a command-line interface tool designed to simplify the management and automation of Cato Networks’ configurations and operations.
594
- It enables users to interact with Cato’s API for tasks such as managing Cato Management Application (CMA) site and account configurations, security policies, retrieving events, etc.\n\n
595
- For assistance in generating syntax for the cli to perform various operations, please refer to the Cato API Explorer application.\n\n
596
- https://github.com/catonetworks/cato-api-explorer
597
- \"""
598
-
599
- parser = argparse.ArgumentParser(prog='catocli', usage='%(prog)s <operationType> <operationName> [options]', description=defaultReadmeStr)
600
- parser.add_argument('--version', action='version', version=catocli.__version__)
601
- parser.add_argument('-H', '--header', action='append', dest='headers', help='Add custom headers in "Key: Value" format. Can be used multiple times.')
602
- parser.add_argument('--headers-file', dest='headers_file', help='Load headers from a file. Each line should contain a header in "Key: Value" format.')
603
- subparsers = parser.add_subparsers()
604
-
605
- # Version command - enhanced with update checking
606
- version_parser = subparsers.add_parser('version', help='Show version information and check for updates')
607
- version_parser.add_argument('--check-updates', action='store_true', help='Force check for updates (ignores cache)')
608
- version_parser.add_argument('--current-only', action='store_true', help='Show only current version')
609
- version_parser.set_defaults(func=show_version_info)
610
-
611
- custom_parsers = custom_parse(subparsers)
612
- raw_parsers = subparsers.add_parser('raw', help='Raw GraphQL', usage=get_help("raw"))
613
- raw_parser = raw_parse(raw_parsers)
614
- query_parser = subparsers.add_parser('query', help='Query', usage='catocli query <operationName> [options]')
615
- query_subparsers = query_parser.add_subparsers(description='valid subcommands', help='additional help')
616
- query_siteLocation_parser = query_siteLocation_parse(query_subparsers)
617
- mutation_parser = subparsers.add_parser('mutation', help='Mutation', usage='catocli mutation <operationName> [options]')
618
- mutation_subparsers = mutation_parser.add_subparsers(description='valid subcommands', help='additional help')
619
-
620
- """
621
- for parserName in parsers:
622
- cliDriverStr += parserName+"_parser = "+parserName+"_parse("+parserName.split("_").pop(0)+"_subparsers)\n"
623
-
624
- cliDriverStr += """
625
-
626
- def parse_headers(header_strings):
627
- headers = {}
628
- if header_strings:
629
- for header_string in header_strings:
630
- if ':' not in header_string:
631
- print(f"ERROR: Invalid header format '{header_string}'. Use 'Key: Value' format.")
632
- exit(1)
633
- key, value = header_string.split(':', 1)
634
- headers[key.strip()] = value.strip()
635
- return headers
636
-
637
- def parse_headers_from_file(file_path):
638
- headers = {}
639
- try:
640
- with open(file_path, 'r') as f:
641
- for line_num, line in enumerate(f, 1):
642
- line = line.strip()
643
- if not line or line.startswith('#'):
644
- # Skip empty lines and comments
645
- continue
646
- if ':' not in line:
647
- print(f"ERROR: Invalid header format in {file_path} at line {line_num}: '{line}'. Use 'Key: Value' format.")
648
- exit(1)
649
- key, value = line.split(':', 1)
650
- headers[key.strip()] = value.strip()
651
- except FileNotFoundError:
652
- print(f"ERROR: Headers file '{file_path}' not found.")
653
- exit(1)
654
- except IOError as e:
655
- print(f"ERROR: Could not read headers file '{file_path}': {e}")
656
- exit(1)
657
- return headers
658
-
659
- def main(args=None):
660
- # Check if no arguments provided or help is requested
661
- if args is None:
662
- args = sys.argv[1:]
663
-
664
- # Show version check when displaying help or when no command specified
665
- if not args or '-h' in args or '--help' in args:
666
- # Check for updates in background (non-blocking)
667
- try:
668
- check_for_updates(show_if_available=True)
669
- except Exception:
670
- # Don't let version check interfere with CLI operation
671
- pass
672
-
673
- args = parser.parse_args(args=args)
674
- try:
675
- # Skip authentication for configure commands
676
- if hasattr(args, 'func') and hasattr(args.func, '__module__') and 'configure' in str(args.func.__module__):
677
- response = args.func(args, None)
678
- else:
679
- # Check if using headers file to determine if we should skip API key
680
- using_headers_file = hasattr(args, 'headers_file') and args.headers_file
681
-
682
- # Get configuration from profiles
683
- configuration = get_configuration(skip_api_key=using_headers_file)
684
-
685
- # Parse custom headers if provided
686
- custom_headers = {}
687
- if hasattr(args, 'headers') and args.headers:
688
- custom_headers.update(parse_headers(args.headers))
689
- if hasattr(args, 'headers_file') and args.headers_file:
690
- custom_headers.update(parse_headers_from_file(args.headers_file))
691
- if custom_headers:
692
- configuration.custom_headers.update(custom_headers)
693
- # Handle account ID override
694
- if args.func.__name__ != "createRawRequest":
695
- if hasattr(args, 'accountID') and args.accountID is not None:
696
- # Command line override takes precedence
697
- configuration.accountID = args.accountID
698
- # Otherwise use the account ID from the profile (already set in get_configuration)
699
- response = args.func(args, configuration)
700
-
701
- if type(response) == ApiException:
702
- print("ERROR! Status code: {}".format(response.status))
703
- print(response)
704
- else:
705
- if response!=None:
706
- print(json.dumps(response[0], sort_keys=True, indent=4))
707
- except Exception as e:
708
- if isinstance(e, AttributeError):
709
- print('Missing arguments. Usage: catocli <operation> -h')
710
- if args.v==True:
711
- print('ERROR: ',e)
712
- traceback.print_exc()
713
- else:
714
- print('ERROR: ',e)
715
- traceback.print_exc()
716
- exit(1)
717
- """
718
- writeFile("../catocli/Utils/clidriver.py",cliDriverStr)
719
-
720
- def writeOperationParsers(catoApiSchema):
721
- parserMapping = {"query":{},"mutation":{}}
722
- ## Write the raw query parser ##
723
- cliDriverStr =f"""
724
- from ..parserApiClient import createRawRequest, get_help
725
-
726
- def raw_parse(raw_parser):
727
- raw_parser.add_argument('json', nargs='?', default='{{}}', help='Query, Variables and opertaionName in JSON format (defaults to empty object if not provided).')
728
- raw_parser.add_argument('-t', const=True, default=False, nargs='?', help='Print GraphQL query without sending API call')
729
- raw_parser.add_argument('-v', const=True, default=False, nargs='?', help='Verbose output')
730
- raw_parser.add_argument('-p', const=True, default=False, nargs='?', help='Pretty print')
731
- raw_parser.add_argument('-H', '--header', action='append', dest='headers', help='Add custom headers in "Key: Value" format. Can be used multiple times.')
732
- raw_parser.add_argument('--headers-file', dest='headers_file', help='Load headers from a file. Each line should contain a header in "Key: Value" format.')
733
- raw_parser.add_argument('--endpoint', dest='endpoint', help='Override the API endpoint URL (e.g., https://api.catonetworks.com/api/v1/graphql2)')
734
- raw_parser.set_defaults(func=createRawRequest,operation_name='raw')
735
- """
736
- parserPath = "../catocli/parsers/raw"
737
- if not os.path.exists(parserPath):
738
- os.makedirs(parserPath)
739
- writeFile(parserPath+"/__init__.py",cliDriverStr)
740
-
741
- ## Write the siteLocation query parser ##
742
- cliDriverStr =f"""
743
- from ..parserApiClient import querySiteLocation, get_help
744
-
745
- def query_siteLocation_parse(query_subparsers):
746
- query_siteLocation_parser = query_subparsers.add_parser('siteLocation',
747
- help='siteLocation local cli query',
748
- usage=get_help("query_siteLocation"))
749
- query_siteLocation_parser.add_argument('json', nargs='?', default='{{}}', help='Variables in JSON format (defaults to empty object if not provided).')
750
- query_siteLocation_parser.add_argument('-accountID', help='Override the CATO_ACCOUNT_ID environment variable with this value.')
751
- query_siteLocation_parser.add_argument('-t', const=True, default=False, nargs='?', help='Print GraphQL query without sending API call')
752
- query_siteLocation_parser.add_argument('-v', const=True, default=False, nargs='?', help='Verbose output')
753
- query_siteLocation_parser.add_argument('-p', const=True, default=False, nargs='?', help='Pretty print')
754
- query_siteLocation_parser.set_defaults(func=querySiteLocation,operation_name='query.siteLocation')
755
- """
756
- parserPath = "../catocli/parsers/query_siteLocation"
757
- if not os.path.exists(parserPath):
758
- os.makedirs(parserPath)
759
- writeFile(parserPath+"/__init__.py",cliDriverStr)
760
-
761
- for operationType in parserMapping:
762
- operationAry = catoApiSchema[operationType]
763
- for operationName in operationAry:
764
- parserMapping = getParserMapping(parserMapping,operationName,operationName,operationAry[operationName])
765
- for operationType in parserMapping:
766
- for operationName in parserMapping[operationType]:
767
- parserName = operationType+"_"+operationName
768
- parser = parserMapping[operationType][operationName]
769
- cliDriverStr = f"""
770
- from ..parserApiClient import createRequest, get_help
771
-
772
- def {parserName}_parse({operationType}_subparsers):
773
- {parserName}_parser = {operationType}_subparsers.add_parser('{operationName}',
774
- help='{operationName}() {operationType} operation',
775
- usage=get_help("{operationType}_{operationName}"))
776
- """
777
- if "path" in parser:
778
- cliDriverStr += f"""
779
- {parserName}_parser.add_argument('json', nargs='?', default='{{}}', help='Variables in JSON format (defaults to empty object if not provided).')
780
- {parserName}_parser.add_argument('-accountID', help='Override the CATO_ACCOUNT_ID environment variable with this value.')
781
- {parserName}_parser.add_argument('-t', const=True, default=False, nargs='?', help='Print GraphQL query without sending API call')
782
- {parserName}_parser.add_argument('-v', const=True, default=False, nargs='?', help='Verbose output')
783
- {parserName}_parser.add_argument('-p', const=True, default=False, nargs='?', help='Pretty print')
784
- {parserName}_parser.add_argument('-H', '--header', action='append', dest='headers', help='Add custom headers in "Key: Value" format. Can be used multiple times.')
785
- {parserName}_parser.add_argument('--headers-file', dest='headers_file', help='Load headers from a file. Each line should contain a header in "Key: Value" format.')
786
- {parserName}_parser.set_defaults(func=createRequest,operation_name='{parserName.replace("_",".")}')
787
- """
788
- else:
789
- cliDriverStr += renderSubParser(parser,operationType+"_"+operationName)
790
- parserPath = "../catocli/parsers/"+parserName
791
- if not os.path.exists(parserPath):
792
- os.makedirs(parserPath)
793
- writeFile(parserPath+"/__init__.py",cliDriverStr)
794
-
795
- def renderSubParser(subParser,parentParserPath):
796
- cliDriverStr = f"""
797
- {parentParserPath}_subparsers = {parentParserPath}_parser.add_subparsers()
798
- """
799
- for subOperationName in subParser:
800
- subOperation = subParser[subOperationName]
801
- subParserPath = parentParserPath.replace(".","_")+"_"+subOperationName
802
- cliDriverStr += f"""
803
- {subParserPath}_parser = {parentParserPath}_subparsers.add_parser('{subOperationName}',
804
- help='{subOperationName}() {parentParserPath.split('_').pop()} operation',
805
- usage=get_help("{subParserPath}"))
806
- """
807
- if "path" in subOperation:
808
- command = parentParserPath.replace("_"," ")+" "+subOperationName
809
- cliDriverStr += f"""
810
- {subParserPath}_parser.add_argument('json', nargs='?', default='{{}}', help='Variables in JSON format (defaults to empty object if not provided).')
811
- {subParserPath}_parser.add_argument('-accountID', help='Override the CATO_ACCOUNT_ID environment variable with this value.')
812
- {subParserPath}_parser.add_argument('-t', const=True, default=False, nargs='?', help='Print GraphQL query without sending API call')
813
- {subParserPath}_parser.add_argument('-v', const=True, default=False, nargs='?', help='Verbose output')
814
- {subParserPath}_parser.add_argument('-p', const=True, default=False, nargs='?', help='Pretty print')
815
- {subParserPath}_parser.add_argument('-H', '--header', action='append', dest='headers', help='Add custom headers in "Key: Value" format. Can be used multiple times.')
816
- {subParserPath}_parser.add_argument('--headers-file', dest='headers_file', help='Load headers from a file. Each line should contain a header in "Key: Value" format.')
817
- {subParserPath}_parser.set_defaults(func=createRequest,operation_name='{subOperation["path"]}')
818
- """
819
- else:
820
- cliDriverStr += renderSubParser(subOperation,subParserPath)
821
- return cliDriverStr
822
-
823
- def writeReadmes(catoApiSchema):
824
- parserMapping = {"query":{},"mutation":{}}
825
-
826
- ## Write the raw query readme ##
827
- readmeStr = """
828
- ## CATO-CLI - raw.graphql
829
- [Click here](https://api.catonetworks.com/documentation/) for documentation on this operation.
830
-
831
- ### Usage for raw.graphql
832
-
833
- `catocli raw -h`
834
-
835
- `catocli raw <json>`
836
-
837
- `catocli raw "$(cat < rawGraphqQL.json)"`
838
-
839
- `catocli raw '{ "query": "query operationNameHere($yourArgument:String!) { field1 field2 }", "variables": { "yourArgument": "string", "accountID": "10949" }, "operationName": "operationNameHere" } '`
840
-
841
- `catocli raw '{ "query": "mutation operationNameHere($yourArgument:String!) { field1 field2 }", "variables": { "yourArgument": "string", "accountID": "10949" }, "operationName": "operationNameHere" } '`
842
-
843
- #### Override API endpoint
844
-
845
- `catocli raw --endpoint https://custom-api.example.com/graphql '<json>'`
846
- """
847
- parserPath = "../catocli/parsers/raw"
848
- if not os.path.exists(parserPath):
849
- os.makedirs(parserPath)
850
- writeFile(parserPath+"/README.md",readmeStr)
851
-
852
- ## Write the query.siteLocation readme ##
853
- readmeStr = """
854
-
855
- ## CATO-CLI - query.siteLocation:
856
-
857
- ### Usage for query.siteLocation:
858
-
859
- `catocli query siteLocation -h`
860
-
861
- `catocli query siteLocation <json>`
862
-
863
- `catocli query siteLocation "$(cat < siteLocation.json)"`
864
-
865
- `catocli query siteLocation '{"filters":[{"search": "Your city here","field":"city","operation":"exact"}]}'`
866
-
867
- `catocli query siteLocation '{"filters":[{"search": "Your Country here","field":"countryName","operation":"startsWith"}]}'`
868
-
869
- `catocli query siteLocation '{"filters":[{"search": "Your stateName here","field":"stateName","operation":"endsWith"}]}'`
870
-
871
- `catocli query siteLocation '{"filters":[{"search": "Your City here","field":"city","operation":"startsWith"},{"search": "Your StateName here","field":"stateName","operation":"endsWith"},{"search": "Your Country here","field":"countryName","operation":"contains"}]}'`
872
-
873
- #### Operation Arguments for query.siteLocation ####
874
- `accountID` [ID] - (required) Unique Identifier of Account.
875
- `filters[]` [Array] - (optional) Array of objects consisting of `search`, `field` and `operation` attributes.
876
- `filters[].search` [String] - (required) String to match countryName, stateName, or city specificed in `filters[].field`.
877
- `filters[].field` [String] - (required) Specify field to match query against, defaults to look for any. Possible values: `countryName`, `stateName`, or `city`.
878
- `filters[].operation` [string] - (required) If a field is specified, operation to match the field value. Possible values: `startsWith`,`endsWith`,`exact`, `contains`.
879
- """
880
- parserPath = "../catocli/parsers/query_siteLocation"
881
- if not os.path.exists(parserPath):
882
- os.makedirs(parserPath)
883
- writeFile(parserPath+"/README.md",readmeStr)
884
-
885
- for operationType in parserMapping:
886
- operationAry = catoApiSchema[operationType]
887
- for operationName in operationAry:
888
- parserMapping = getParserMapping(parserMapping,operationName,operationName,operationAry[operationName])
889
- for operationType in parserMapping:
890
- for operationName in parserMapping[operationType]:
891
- parserName = operationType+"_"+operationName
892
- parser = parserMapping[operationType][operationName]
893
- operationPath = operationType+"."+operationName
894
- operationCmd = operationType+" "+operationName
895
- readmeStr = f"""
896
- ## CATO-CLI - {operationPath}:
897
- [Click here](https://api.catonetworks.com/documentation/#{operationType}-{operationName}) for documentation on this operation.
898
-
899
- ### Usage for {operationPath}:
900
-
901
- `catocli {operationCmd} -h`
902
- """
903
- if "path" in parser:
904
- readmeStr += f"""
905
- `catocli {operationCmd} <json>`
906
-
907
- `catocli {operationCmd} "$(cat < {operationName}.json)"`
908
-
909
- `catocli {operationCmd} '{json.dumps(parser["example"])}'`
910
-
911
- #### Operation Arguments for {operationPath} ####
912
- """
913
- for argName in parser["args"]:
914
- arg = parser["args"][argName]
915
- readmeStr += '`'+argName+'` ['+arg["type"]+'] - '
916
- readmeStr += '('+arg["required"]+') '+arg["description"]+' '
917
- readmeStr += 'Default Value: '+str(arg["values"]) if len(arg["values"])>0 else ""
918
- readmeStr += "\n"
919
- parserPath = "../catocli/parsers/"+parserName
920
- if not os.path.exists(parserPath):
921
- os.makedirs(parserPath)
922
- writeFile(parserPath+"/README.md",readmeStr)
923
- else:
924
- parserPath = "../catocli/parsers/"+parserName
925
- if not os.path.exists(parserPath):
926
- os.makedirs(parserPath)
927
- writeFile(parserPath+"/README.md",readmeStr)
928
- renderSubReadme(parser,operationType,operationType+"."+operationName)
929
-
930
- def renderSubReadme(subParser,operationType,parentOperationPath):
931
- for subOperationName in subParser:
932
- subOperation = subParser[subOperationName]
933
- subOperationPath = parentOperationPath+"."+subOperationName
934
- subOperationCmd = parentOperationPath.replace("."," ")+" "+subOperationName
935
- parserPath = "../catocli/parsers/"+subOperationPath.replace(".","_")
936
- readmeStr = f"""
937
- ## CATO-CLI - {parentOperationPath}.{subOperationName}:
938
- [Click here](https://api.catonetworks.com/documentation/#{operationType}-{subOperationName}) for documentation on this operation.
939
-
940
- ### Usage for {subOperationPath}:
941
-
942
- `catocli {subOperationCmd} -h`
943
- """
944
- if "path" in subOperation:
945
- readmeStr += f"""
946
- `catocli {subOperationCmd} <json>`
947
-
948
- `catocli {subOperationCmd} "$(cat < {subOperationName}.json)"`
949
-
950
- `catocli {subOperationCmd} '{json.dumps(subOperation["example"])}'`
951
-
952
- #### Operation Arguments for {subOperationPath} ####
953
- """
954
- for argName in subOperation["args"]:
955
- arg = subOperation["args"][argName]
956
- readmeStr += '`'+argName+'` ['+arg["type"]+'] - '
957
- readmeStr += '('+arg["required"]+') '+arg["description"]+' '
958
- readmeStr += 'Default Value: '+str(arg["values"]) if len(arg["values"])>0 else ""
959
- readmeStr += "\n"
960
- if not os.path.exists(parserPath):
961
- os.makedirs(parserPath)
962
- writeFile(parserPath+"/README.md",readmeStr)
963
- else:
964
- if not os.path.exists(parserPath):
965
- os.makedirs(parserPath)
966
- writeFile(parserPath+"/README.md",readmeStr)
967
- renderSubReadme(subOperation,operationType,subOperationPath)
968
-
969
- def getParserMapping(curParser,curPath,operationFullPath,operation):
970
- parserObj = {
971
- "path":operationFullPath,
972
- "args":{},
973
- # "example":"N/A",
974
- "example":operation["variablesPayload"]
975
- }
976
- for argName in operation["operationArgs"]:
977
- arg = operation["operationArgs"][argName]
978
- values = []
979
- if "definition" in arg["type"] and "enumValues" in arg["type"]["definition"] and arg["type"]["definition"]["enumValues"]!=None:
980
- for enumValue in arg["type"]["definition"]["enumValues"]:
981
- values.append(enumValue["name"])
982
- parserObj["args"][arg["varName"]] = {
983
- "name":arg["name"],
984
- "description":"N/A" if arg["description"]==None else arg["description"],
985
- "type":arg["type"]["name"]+("[]" if "LIST" in arg["type"]["kind"] else ""),
986
- "required": "required" if arg["required"]==True else "optional",
987
- "values":values
988
- }
989
- pAry = curPath.split(".")
990
- pathCount = len(curPath.split("."))
991
- if pAry[0] not in curParser:
992
- curParser[pAry[0]] = {}
993
- if pathCount == 2:
994
- curParser[pAry[0]][pAry[1]] = parserObj
995
- else:
996
- if pAry[1] not in curParser[pAry[0]]:
997
- curParser[pAry[0]][pAry[1]] = {}
998
- if pathCount == 3:
999
- curParser[pAry[0]][pAry[1]][pAry[2]] = parserObj
1000
- else:
1001
- if pAry[2] not in curParser[pAry[0]][pAry[1]]:
1002
- curParser[pAry[0]][pAry[1]][pAry[2]] = {}
1003
- if pathCount == 4:
1004
- curParser[pAry[0]][pAry[1]][pAry[2]][pAry[3]] = parserObj
1005
- else:
1006
- if pAry[3] not in curParser[pAry[0]][pAry[1]][pAry[2]]:
1007
- curParser[pAry[0]][pAry[1]][pAry[2]][pAry[3]] = {}
1008
- if pathCount == 5:
1009
- curParser[pAry[0]][pAry[1]][pAry[2]][pAry[3]][pAry[4]] = parserObj
1010
- else:
1011
- if pAry[4] not in curParser[pAry[0]][pAry[1]][pAry[2]][pAry[3]]:
1012
- curParser[pAry[0]][pAry[1]][pAry[2]][pAry[3]][pAry[4]] = {}
1013
- if pathCount == 6:
1014
- curParser[pAry[0]][pAry[1]][pAry[2]][pAry[3]][pAry[4]][pAry[5]] = parserObj
1015
- return curParser
1016
-
1017
- def send(api_key,query,variables={},operationName=None):
1018
- headers = { 'x-api-key': api_key,'Content-Type':'application/json'}
1019
- no_verify = ssl._create_unverified_context()
1020
- request = urllib.request.Request(url='https://api.catonetworks.com/api/v1/graphql2',
1021
- data=json.dumps(query).encode("ascii"),headers=headers)
1022
- response = urllib.request.urlopen(request, context=no_verify, timeout=60)
1023
- result_data = response.read()
1024
- result = json.loads(result_data)
1025
- if "errors" in result:
1026
- logging.warning(f"API error: {result_data}")
1027
- return False,result
1028
- return True,result
1029
-
1030
-
1031
- ################### adding functions local to generate dynamic payloads ####################
1032
- def generateGraphqlPayload(variablesObj,operation,operationName):
1033
- indent = " "
1034
- queryStr = ""
1035
- variableStr = ""
1036
- for varName in variablesObj:
1037
- if (varName in operation["operationArgs"]):
1038
- variableStr += operation["operationArgs"][varName]["requestStr"]
1039
- operationAry = operationName.split(".")
1040
- operationType = operationAry.pop(0)
1041
- queryStr = operationType + " "
1042
- queryStr += renderCamelCase(".".join(operationAry))
1043
- queryStr += " ( " + variableStr + ") {\n"
1044
- queryStr += indent + operation["name"] + " ( "
1045
- for argName in operation["args"]:
1046
- arg = operation["args"][argName]
1047
- if arg["varName"] in variablesObj:
1048
- queryStr += arg["responseStr"]
1049
- queryStr += ") {\n" + renderArgsAndFields("", variablesObj, operation, operation["type"]["definition"], " ") + " }"
1050
- queryStr += indent + "\n}";
1051
- body = {
1052
- "query":queryStr,
1053
- "variables":variablesObj,
1054
- "operationName":renderCamelCase(".".join(operationAry)),
1055
- }
1056
- return body
1057
-
1058
- def renderArgsAndFields(responseArgStr, variablesObj, curOperation, definition, indent):
1059
- for fieldName in definition['fields']:
1060
- field = definition['fields'][fieldName]
1061
- field_name = field['alias'] if 'alias' in field else field['name']
1062
- responseArgStr += indent + field_name
1063
- if field.get("args") and not isinstance(field['args'], list):
1064
- if (len(list(field['args'].keys()))>0):
1065
- argsPresent = False
1066
- argStr = " ( "
1067
- for argName in field['args']:
1068
- arg = field['args'][argName]
1069
- if arg["varName"] in variablesObj:
1070
- argStr += arg['responseStr'] + " "
1071
- argsPresent = True
1072
- argStr += ") "
1073
- if argsPresent==True:
1074
- responseArgStr += argStr
1075
- if field.get("type") and field['type'].get('definition') and field['type']['definition']['fields'] is not None:
1076
- responseArgStr += " {\n"
1077
- for subfieldIndex in field['type']['definition']['fields']:
1078
- subfield = field['type']['definition']['fields'][subfieldIndex]
1079
- subfield_name = subfield['alias'] if 'alias' in subfield else subfield['name']
1080
- responseArgStr += indent + " " + subfield_name
1081
- if subfield.get("args") and len(list(subfield["args"].keys()))>0:
1082
- argsPresent = False
1083
- subArgStr = " ( "
1084
- for argName in subfield['args']:
1085
- arg = subfield['args'][argName]
1086
- if arg["varName"] in variablesObj:
1087
- argsPresent = True
1088
- subArgStr += arg['responseStr'] + " "
1089
- subArgStr += " )"
1090
- if argsPresent==True:
1091
- responseArgStr += subArgStr
1092
- if subfield.get("type") and subfield['type'].get("definition") and (subfield['type']['definition'].get("fields") or subfield['type']['definition'].get('inputFields')):
1093
- responseArgStr += " {\n"
1094
- responseArgStr = renderArgsAndFields(responseArgStr, variablesObj, curOperation, subfield['type']['definition'], indent + " ")
1095
- if subfield['type']['definition'].get('possibleTypes'):
1096
- for possibleTypeName in subfield['type']['definition']['possibleTypes']:
1097
- possibleType = subfield['type']['definition']['possibleTypes'][possibleTypeName]
1098
- responseArgStr += indent + " ... on " + possibleType['name'] + " {\n"
1099
- if possibleType.get('fields') or possibleType.get('inputFields'):
1100
- responseArgStr = renderArgsAndFields(responseArgStr, variablesObj, curOperation, possibleType, indent + " ")
1101
- responseArgStr += indent + " }\n"
1102
- responseArgStr += indent + " }"
1103
- elif subfield.get('type') and subfield['type'].get('definition') and subfield['type']['definition'].get('possibleTypes'):
1104
- responseArgStr += " {\n"
1105
- responseArgStr += indent + " __typename\n"
1106
- for possibleTypeName in subfield['type']['definition']['possibleTypes']:
1107
- possibleType = subfield['type']['definition']['possibleTypes'][possibleTypeName]
1108
- responseArgStr += indent + " ... on " + possibleType['name'] + " {\n"
1109
- if possibleType.get('fields') or possibleType.get('inputFields'):
1110
- responseArgStr = renderArgsAndFields(responseArgStr, variablesObj, curOperation, possibleType, indent + " ")
1111
- responseArgStr += indent + " }\n"
1112
- responseArgStr += indent + " }\n"
1113
- responseArgStr += "\n"
1114
- if field['type']['definition'].get('possibleTypes'):
1115
- for possibleTypeName in field['type']['definition']['possibleTypes']:
1116
- possibleType = field['type']['definition']['possibleTypes'][possibleTypeName]
1117
- responseArgStr += indent + " ... on " + possibleType['name'] + " {\n"
1118
- if possibleType.get('fields') or possibleType.get('inputFields'):
1119
- responseArgStr = renderArgsAndFields(responseArgStr, variablesObj, curOperation, possibleType, indent + " ")
1120
- responseArgStr += indent + " }\n"
1121
- responseArgStr += indent + "}\n"
1122
- if field.get('type') and field['type'].get('definition') and field['type']['definition'].get('inputFields'):
1123
- responseArgStr += " {\n"
1124
- for subfieldName in field['type']['definition'].get('inputFields'):
1125
- subfield = field['type']['definition']['inputFields'][subfieldName]
1126
- subfield_name = subfield['alias'] if 'alias' in subfield else subfield['name']
1127
- responseArgStr += indent + " " + subfield_name
1128
- if subfield.get('type') and subfield['type'].get('definition') and (subfield['type']['definition'].get('fields') or subfield['type']['definition'].get('inputFields')):
1129
- responseArgStr += " {\n"
1130
- responseArgStr = renderArgsAndFields(responseArgStr, variablesObj, curOperation, subfield['type']['definition'], indent + " ")
1131
- responseArgStr += indent + " }\n"
1132
- if field['type']['definition'].get('possibleTypes'):
1133
- for possibleTypeName in field['type']['definition']['possibleTypes']:
1134
- possibleType = field['type']['definition']['possibleTypes'][possibleTypeName]
1135
- responseArgStr += indent + "... on " + possibleType['name'] + " {\n"
1136
- if possibleType.get('fields') or possibleType.get('inputFields'):
1137
- responseArgStr = renderArgsAndFields(responseArgStr, variablesObj, curOperation, possibleType, indent + " ")
1138
- responseArgStr += indent + " }\n"
1139
- responseArgStr += indent + "}\n"
1140
- responseArgStr += "\n"
1141
- return responseArgStr