Closed jay-eleven closed 2 years ago
Jay,
Your list is doable but we;ll need to figure out a way I can test as I'm not a reseller.
Ross
Ross,
I have access to a reseller account, so if you're willing to code, I'm willing to test!
Now the hard part; naming; accounts and customer are already being used individually. How about?
gam print|show channelcustomers <AccountID>
gam print|show channelentitlements <AccountID> <CustomerID>
gam print|show channeloffers <AccountID>
gam print|show channelproducts <AccountID>
gam print|show channelskus <AccountID> <ProductID>
channelxxxxxx
seems the perfect choice. This would be aligned with the Reseller API's resoldxxxxx
commands.
<AccountID>
, <CustomerID>
and <ProductID>
look like perfectly good parameter names.
print|show
would need to support JSON output.
The standard filter
, pageSize
, fields
, etc... parameters (were available) would still work, right?
<ChannelCustomerField> ::=
alternateemail |
channelpartnerid |
cloudidentityid |
cloudidentityinfo |
createtime |
domain |
languagecode |
name |
orgdisplayname |
orgpostaladdress |
primarycontactinfo |
updatetime
<ChannelCustomerFieldList> ::= "<ChannelCustomerField>(,<ChannelCustomerField>)*"
gam print channelcustomers [todrive <ToDriveAttribute>*]
accountid <AccountID> [filter <String>]
[fields <ChannelCustomerFieldList>]
[maxresults <Integer>]
[formatjson [quotechar <Character>]]
gam show channelcustomers
accountid <AccountID> [filter <String>]
[fields <ChannelCustomerFieldList>]
[maxresults <Integer>]
[formatjson]
<ChannelCustomerEntitlementField> ::=
associationinfo |
commitmentsettings |
createtime |
name |
offer |
parameters |
provisionedservice |
provisioningstate |
purchaseorderid |
suspensionreasons |
trialsettings |
updatetime
<ChannelCustomerEntitlementFieldList> ::= "<ChannelCustomerEntitlementField>(,<ChannelCustomerEntitlementField>)*"
gam print channelcustomercentitlements [todrive <ToDriveAttribute>*]
(accountid <AccountID> customerid <CustomerID>)|(name accounts/<AccountID/customers/<CustomerID>)
[fields <ChannelCustomerEntitlementsFieldList>]
[maxresults <Integer>]
[formatjson [quotechar <Character>]]
gam show channelcustomerentitlements
(accountid <AccountID> customerid <CustomerID>)|(name accounts/<AccountID/customers/<CustomerID>)
[fields <ChannelCustomerEntitlementsFieldList>]
[maxresults <Integer>]
[formatjson]
<ChannelCustomerOfferField> ::=
constraints |
endtime |
marketinginfo |
name |
parameterdefinitions |
plan |
pricebyresources |
sku |
starttime
<ChannelOfferFieldList> ::= "<ChannelOfferField>(,<ChannelOfferField>)*"
gam print channeloffers [todrive <ToDriveAttribute>*]
accountid <AccountID> [filter <String>] [language <LanguageCode]
[fields <ChannelOfferFieldList>]
[maxresults <Integer>]
[formatjson [quotechar <Character>]]
gam show channeloffers
accountid <AccountID> [filter <String>] [language <LanguageCode]
[fields <ChannelOfferFieldList>]
[maxresults <Integer>]
[formatjson]
<ChannelProductField> ::=
marketinginfo |
name
<ChannelProductFieldList> ::= "<ChannelProductField>(,<ChannelProductField>)*"
gam print channelproducts [todrive <ToDriveAttribute>*]
accountid <AccountID> [language <LanguageCode]
[fields <ChannelProductFieldList>]
[maxresults <Integer>]
[formatjson [quotechar <Character>]]
gam show channelproducts
accountid <AccountID> [language <LanguageCode]
[fields <ChannelProductFieldList>]
[maxresults <Integer>]
[formatjson]
<ChannelSKUField> ::=
marketinginfo |
name |
product
<ChannelSKUFieldList> ::= "<ChannelSKUField>(,<ChannelSKUField>)*"
gam print channelskus [todrive <ToDriveAttribute>*]
accountid <AccountID> [language <LanguageCode] [productid <ProductID>]
[fields <ChannelSKUFieldList>]
[maxresults <Integer>]
[formatjson [quotechar <Character>]]
gam show channelskus
accountid <AccountID> [language <LanguageCode] [productid <ProductID>]
[fields <ChannelSKUFieldList>]
[maxresults <Integer>]
[formatjson]
This looks awesome!
Minor typos:
name accounts/<AccountID/customers/<CustomerID>
---> name accounts/<AccountID>/customers/<CustomerID>
language <LanguageCode
---> language <LanguageCode>
Hmmmm... How can I test? 🫣
Go here: https://github.com/taers232c/GAMADV-XTD3/releases/edit/untagged-79d2c4b53e0146b59041 Grab a version At the moment, the Mac Version won't build.
gam update project gam oauth create
In addition to testing if the command works, test giving invalid AccountIDs, customerIDs and ProductIDS.
Mmmm... The link doesn't work for me: I get a 404. Maybe lack of permissions? 😅
https://github.com/taers232c/GAMADV-XTD3/releases
Download from the 6.18.00 Draft.
On it!
OK, I'm in business:
jay@cloudshell:~/gambeta$ ./gambeta
GAMADV-XTD3 6.18.00 - https://github.com/taers232c/GAMADV-XTD3 - pyinstaller
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.10.3 64-bit final
Linux Debian 11 Bullseye x86_64
Path: /home/jay/gambeta
Config File: /home/jay/.gam/gam.cfg, Section: reseller, customer_id: my_customer, domain:
Help: Syntax in file /home/jay/gambeta/GamCommands.txt
Help: Documentation is at https://github.com/taers232c/GAMADV-XTD3/wiki
Extracted new gam to its own dir to make sure it's the one I use.
jay@cloudshell:~/gambeta$ ./gambeta show channelcustomers accountid ThisWillError
Channel Customer: accounts/ThisWillError, Show Failed: <eye3 title='/AuthzService.BatchCheckPrivileges, INVALID_ARGUMENT'/> APPLICATION_ERROR;google.internal.cloud.channel.v1/AuthzService.BatchCheckPrivileges;CustomerId : ThisWillError is invalid.
com.google.apps.framework.request.BadRequestException: CustomerId : ThisWillError is invalid.;AppErrorCode=3;StartTimeMs=1648481251973;unknown;ResFormat=AUTOMATIC;ServerTimeSec=0.009914624;LogBytes=256;FailFast;EffSecLevel=none;ReqFormat=AUTOMATIC;ReqID=6ef3a456b15b1545;GlobalID=0;Server=[::1]:0
jay@cloudshell:~/gambeta$
Good, the API is set up, scopes are granted and gam works correctly when a fake accountid is used. I've found some things that need fixing/tuning. How do you want me to report back? In this same thread? Should I compile my findings/tests in a separate doc I share with you?
In print channelcustomerentitlements,
In print channelskus, try with invalid productid, e,g,, productid nv:xxxxxx
Jay,
Email me suggestions; we can certainly Meet/Zoom as well to discuss.
Super impressed! Almost everything works and I just found very minor nuances. Good job!! 👏
accountid
: works as expectedaccountid
: I get a quota error sometimes. Please default to maxresults=50
(API's max)filter
: 400 bad request. Filter example: cloud_identity_id="someId"
Filter's surrounding "
are being stripped. Those are needed by the endpoint:
ERROR: JSON: {'error': {'code': 400,
'message': 'cloud_identity_id value in the filter must be surrounded by ".',
'status': 'INVALID_ARGUMENT',
[...]
'errorMessages': [{
'errorMessage': 'The filter expression provided in the request is malformed or unsupported.'
[...]
I tried using double and triple "
but everything was stripped.
fields
is broken:
Traceback (most recent call last):
File "__init__.py", line 61423, in ProcessGAMCommand
File "__init__.py", line 13230, in doPrintShowChannelCustomers
File "__init__.py", line 13144, in doPrintShowChannelItems
KeyError: 'fields'
maxresults=100
(API's max)fields
is broken:
Traceback (most recent call last):
File "__init__.py", line 61423, in ProcessGAMCommand
File "__init__.py", line 13243, in doPrintShowChannelCustomerEntitlements
File "__init__.py", line 13144, in doPrintShowChannelItems
KeyError: 'fields'
maxresults=1000
(API's max)filter
parameter works here because it doesn't need "
! 😱 Example filter: name=accounts/some_account/offers/some_offer
fields
is broken:
Traceback (most recent call last):
File "__init__.py", line 61423, in ProcessGAMCommand
File "__init__.py", line 13256, in doPrintShowChannelOffers
File "__init__.py", line 13144, in doPrintShowChannelItems
KeyError: 'fields'
maxresults=1000
(API's max)fields
is broken:
Traceback (most recent call last):
File "__init__.py", line 61423, in ProcessGAMCommand
File "__init__.py", line 13269, in doPrintShowChannelProducts
File "__init__.py", line 13144, in doPrintShowChannelItems
KeyError: 'fields'
accountid
works as expected. Please default maxresults=1000
(API's max)productid
are different from the Reseller API, at this point I'm not 100% sure they can be validated against a known table of Ids. These can be removed from the docs as well. Eg: productid 20gb
raises error:
ERROR: JSON: {'error': {'code': 400,
'message': 'Violation in ListSkusRequest.parent: field predicate failed: matches($, `^products/[a-zA-Z0-9]+$`) or matches($, `^products/-$`)',
'status': 'INVALID_ARGUMENT'}}
Specifying a Channel Services productid
obtained from channelproducts
via nv:
works perfectly: productid nv:products/Uv2DWGG1lwqAXX
. Note that products/
must be prepended to the productid
passed as parameter value.
formatjson
does not work: ERROR: Missing argument: Expected <ProductID>
even though productid
was declaredfields
is broken:
ERROR: Invalid choice (name): Expected
<101001|101005|101031|101033|101034|101035|101037|
Google-Apps|Google-Chrome-Device-Management|Google-Drive-storage|Google-Vault>
I'm not sure if these are common to all resellers or are particular to us. It does not make sense to have a table with them if they're not the same for all. When the fields
parameter starts working, I can provide a full listing of what I see.
name,marketingInfo.displayName
products/UADAVyrVqM6grP,Google Workspace
products/UjR5LV8LAKzn6W,Google Workspace Archived User
products/Uo275Em5296qqK,Google Vault
products/Uv2DWGG1lwqAXX,Google Drive storage
[...]
Same as with Product Ids. I'm not sure if these are common to all resellers or are particular to us. It does not make sense to have a table with them if they're not the same for all. When the fields
parameter starts working, I can provide a full listing of what I see.
name,marketingInfo.displayName
products/UADAVyrVqM6grP/skus/S6sH51ibL9dQY8,Google Workspace Enterprise Starter
products/UADAVyrVqM6grP/skus/SEVlaChVhiSE2J,Google Workspace Business Plus
[...]
The accountid
parameter should be optional for gam. If not present, pull the customer_id
variable from the gam.cfg
file, it will work.
showcustomers
ERROR: Invalid choice (x): Expected <admin| [...] |channelcustomer|channelcustomerentitlement|channeloffer|channelproduct|channelsku [...]
gam
accepts both singular and plural 🤩
Suggestion, update docs to show both forms are accepted 😎Please, let me know if you need help updating the docs to remove SKU, Product...
Thanks for the detailed info.
Do you have a moment for a Meet?
New Draft posted at 4:20PM PDT.
For print channelcustomerentitlements, I need an accountID and customerID. Should the customerID default to gam.cfg/customer_id?
Would it make sense to replace <AccountID>
with <ResellerID>
and add reseller_id
to gam.cfg
?
Get latest draft 2022-02-28 08:56 PDT
Added reseller_id to gam.cfg
Replaced accountid <AccountID>
with resellerid <ResellerID>
; default is gam.cfg/reseller_id
if defined, else gam.cfg/customer_id
Hi Ross! My timezone is GMT+2, so bear with me if I'm not responsive at times... 😅 I posted my report just before going to bed... 😴
Added reseller_id to gam.cfg Replaced accountid
with resellerid ; default is gam.cfg/reseller_id if defined, else gam.cfg/customer_id
This is the most flexible solution. I don't think it's needed, but having it is the safest bet. Let me test and I'll report back.
Getting latest draft and testing...
Get new draft, 2022-03-29, 10:12 PDT
Fixes getting a list of fields
Here it goes.
accountid
-> resellerid
I've tried several combinations and everything works as expected. Defaulting to gam.cfg/customer_id
if gam.cfg/reseller_id
is not defined works as expected.
Everything works as expected except:
filter
: 400 bad request. Filter example: cloud_identity_id="someId"
Channel Customer: accounts/someId,
Print Failed: cloud_identity_id value in the filter must be surrounded by ".
fields
is broken in show
and ignored in print
(all fields are shown)Everything works as expected except:
fields
is broken in show
and ignored in print
(all fields are shown)Everything works as expected except:
fields
is broken in show
and ignored in print
(all fields are shown)Everything works as expected except:
fields
is broken in show
and ignored in print
(all fields are shown)Everything works as expected except:
fields
is broken in show
and ignored in print
(all fields are shown)Oh! I'll get the new draft!
Show me the command line for channelcustomers filter
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Channel#display-channel-customers
./gambeta show channelcustomers filter cloud_identity_id="someid"
This is a command line issue, not a GAM issue:
Linux/MacOS
./gambeta show channelcustomers filter 'cloud_identity_id="someid"'
Windows Command Prompt
./gambeta show channelcustomers filter "cloud_identity_id=\"someid\""
Windows PowerShell
./gambeta show channelcustomers filter 'cloud_identity_id=\"someid\"'
I can confirm filter
works: ./gambeta print channelcustomers filter 'domain:"something*" AND org_display_name:"something_else *"'
prints what it should
Testing fields
...
Added filter
examples to docs
Almost done!!!
fields
in channel* show
commands doesn't work. Eg. ./gambeta show channeloffers fields name
:
File "__init__.py", line 61417, in ProcessGAMCommand
File "__init__.py", line 13250, in doPrintShowChannelOffers
File "__init__.py", line 13144, in doPrintShowChannelItems
AttributeError: 'NoneType' object has no attribute 'AddField'
fields
in channel* print
commands almost works. Eg. ./gambeta print channel* fields name
:
name,sku,startTime,endTime
accounts/someId/offers/S07jzJ4lP,,,
accounts/someId/offers/S0NnUiMpU,,,
accounts/someId/offers/S0b3RL2be,,,
accounts/someId/offers/S085nsuak,,,
[...]
Extra field names and ,
printed. Expected output:
name
accounts/someId/offers/S07jzJ4lP
accounts/someId/offers/S0NnUiMpU
accounts/someId/offers/S0b3RL2be
accounts/someId/offers/S085nsuak
[...]
Have you finished testing, should I publish?
fields
needs some love yet... 😅
OK, I'll wait for further news. Thanks for all of your help.
Check my latest report on fields
just before you asked if you could publish: https://github.com/taers232c/GAMADV-XTD3/issues/258#issuecomment-1082235463
On the case.
New draft available.
On Tue, Mar 29, 2022 at 11:36 AM Jay @.***> wrote:
Check my latest report on fields just before you asked if you could publish: #258 (comment) https://github.com/taers232c/GAMADV-XTD3/issues/258#issuecomment-1082235463
— Reply to this email directly, view it on GitHub https://github.com/taers232c/GAMADV-XTD3/issues/258#issuecomment-1082240636, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACCTYL2WHDEYRCOFAQ6VIVDVCNEUFANCNFSM5RXDTQDQ . You are receiving this because you commented.Message ID: @.***>
-- Ross Scroggs @.***
On it
Everything works! Great job Ross! 👍
Published.
Thanks
On Tue, Mar 29, 2022 at 12:53 PM Jay @.***> wrote:
Everything works! Great job Ross! 👍
— Reply to this email directly, view it on GitHub https://github.com/taers232c/GAMADV-XTD3/issues/258#issuecomment-1082312958, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACCTYL5BTHRU5LTBTEA5FUDVCNNTTANCNFSM5RXDTQDQ . You are receiving this because you commented.Message ID: @.***>
-- Ross Scroggs @.***
Hi Ross!
I understand that the target audience for this request is (very) small, but... how feasible is it to implement a handful of read only methods from the Cloud Channel API? These are:
These methods use the https://www.googleapis.com/auth/apps.order scope which is already being used for the Reseller API methods, so it should be easy to integrate them.
Thoughts? 😅