Skip to content

Commit

Permalink
Added option archive to `gam <UserTypeEntity> update license <NewSK…
Browse files Browse the repository at this point in the history
…UID> from <OldSKUID>`
  • Loading branch information
taers232c committed Dec 18, 2024
1 parent 89970bb commit a9e28e9
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 4 deletions.
3 changes: 2 additions & 1 deletion src/GamCommands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7821,7 +7821,8 @@ gam <UserTypeEntity> delete noteacl <NotesNameEntity>
# Users - Licenses

gam <UserTypeEntity> create|add license <SKUIDList> [product|productid <ProductID>] [preview] [actioncsv]
gam <UserTypeEntity> update license <SKUID> [product|productid <ProductID>] [from] <SKUID> [preview] [actioncsv]
gam <UserTypeEntity> update license <NewSKUID> [product|productid <ProductID>] [from] <OldSKUID>
[preview|archive] [actioncsv]
gam <UserTypeEntity> delete license <SKUIDList> [product|productid <ProductID>] [preview] [actioncsv]
gam <UserTypeEntity> sync license <SKUIDList> [product|productid <ProductID>] [addonly|removeonly] [allskus|onesku] [preview] [actioncsv]

Expand Down
17 changes: 17 additions & 0 deletions src/GamUpdate.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
7.02.03

Added option `archive` to `gam <UserTypeEntity> update license <NewSKUID> from <OldSKUID>` that causes GAM
to archive `<UserTypeEntity>` after updating their license to `<NewSKUID>`. This will be used when you want to
archive a user with a non-archivable license. The `<NewSKUID>` license is assigned to the user and it then converts
to the equivalent Archived User license when the user is archived.

`<NewSKUID>` must be one of the following SKUs:
```
Google-Apps-Unlimited - G Suite Business
1010020020 - Google Workspace Enterprise Plus
1010020025 - Google Workspace Business Plus
1010020026 - Google Workspace Enterprise Standard
1010020027 - Google Workspace Business Starter
1010020028 - Google Workspace Business Standard
```

7.02.02

Updated `gam <UserTypeEntity> archive messages <GroupItem>` to retry the following unexpected error
Expand Down
30 changes: 27 additions & 3 deletions src/gam/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"""

__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.02.02'
__version__ = '7.02.03'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'

#pylint: disable=wrong-import-position
Expand Down Expand Up @@ -67173,7 +67173,7 @@ def printUserGroupsList(users):

def getLicenseParameters(operation):
lic = buildGAPIObject(API.LICENSING)
parameters = {LICENSE_PRODUCT_SKUIDS: [], 'csvPF': None, 'preview': False, 'syncOperation': 'addremove', 'syncACLsMode': None}
parameters = {LICENSE_PRODUCT_SKUIDS: [], 'csvPF': None, 'preview': False, 'syncOperation': 'addremove', 'syncACLsMode': None, 'archive': False}
skuLocation = Cmd.Location()
if operation != 'patch':
parameters[LICENSE_PRODUCT_SKUIDS] = getGoogleSKUList(allowUnknownProduct=True)
Expand Down Expand Up @@ -67203,6 +67203,10 @@ def getLicenseParameters(operation):
if operation == 'patch':
titles.insert(2, 'oldskuId')
parameters['csvPF'] = CSVPrintFile(titles)
elif operation == 'patch' and myarg == 'archive':
if skuId not in SKU.ARCHIVABLE_SKUS:
usageErrorExit(Msg.SKU_HAS_NO_MATCHING_ARCHIVED_USER_SKU.format(skuId))
parameters['archive'] = True
else:
unknownArgumentExit()
for productSku in parameters[LICENSE_PRODUCT_SKUIDS]:
Expand Down Expand Up @@ -67308,13 +67312,17 @@ def createLicense(users):
if parameters['csvPF']:
parameters['csvPF'].writeCSVfile('Create Licenses')

# gam <UserTypeEntity> update license <SKUID> [product|productid <ProductID>] [from] <SKUID> [preview] [actioncsv]
# gam <UserTypeEntity> update license <SKUID> [product|productid <ProductID>] [from] <SKUID>
# [preview] [actioncsv] [archive]
def updateLicense(users):
lic, parameters = getLicenseParameters('patch')
j, jcount, users = getEntityArgument(users)
Act.Set([Act.UPDATE, Act.UPDATE_PREVIEW][parameters['preview']])
cd = None
if parameters['preview']:
message = Act.PREVIEW
elif parameters['archive']:
cd = buildGAPIObject(API.DIRECTORY)
productId, skuId, oldSkuId = parameters[LICENSE_PRODUCT_SKUIDS][0]
body = {'skuId': skuId}
entityPerformActionModifierNumItems([Ent.LICENSE, SKU.skuIdToDisplayName(skuId)], Msg.FOR, jcount, Ent.USER)
Expand All @@ -67340,6 +67348,22 @@ def updateLicense(users):
except GAPI.userNotFound as e:
message = str(e)
entityUnknownWarning(Ent.USER, user, j, jcount)
if parameters['archive'] and message == Act.SUCCESS:
Act.Set(Act.ARCHIVE)
try:
callGAPI(cd.users(), 'update',
throwReasons=[GAPI.USER_NOT_FOUND, GAPI.DOMAIN_NOT_FOUND,
GAPI.FORBIDDEN, GAPI.BAD_REQUEST,
GAPI.INSUFFICIENT_ARCHIVED_USER_LICENSES],
retryReasons=[GAPI.INSUFFICIENT_ARCHIVED_USER_LICENSES],
userKey=user, body={'archived': True})
entityActionPerformed([Ent.USER, user], j, jcount)
except GAPI.userNotFound:
entityUnknownWarning(Ent.USER, user, j, jcount)
except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden, GAPI.badRequest,
GAPI.insufficientArchivedUserLicenses) as e:
entityActionFailedWarning([Ent.USER, user], str(e), j, jcount)
Act.Set(Act.UPDATE)
if parameters['csvPF']:
_writeLicenseAction(productId, skuId, oldSkuId, parameters, user, Act.UPDATE, message)
Ind.Decrement()
Expand Down
1 change: 1 addition & 0 deletions src/gam/gamlib/glmsgs.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@
SERVICE_NOT_APPLICABLE_THIS_ADDRESS = 'Service not applicable for this address: {0}'
SERVICE_NOT_ENABLED = '{0} Service/App not enabled'
SHORTCUT_TARGET_CAPABILITY_IS_FALSE = '{0} capability {1} is False'
SKU_HAS_NO_MATCHING_ARCHIVED_USER_SKU = 'SKU {0} has no matching Archived User SKU'
STARTING_THREAD = 'Starting thread'
STATISTICS_COPY_FILE = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Copy Failed: {5}, Not copyable: {6}, In skipids: {7}, Permissions Failed: {8}, Protected Ranges Failed: {9}'
STATISTICS_COPY_FOLDER = 'Total: {0}, Copied: {1}, Shortcut created {2}, Shortcut exists {3}, Duplicate: {4}, Merged: {5}, Copy Failed: {6}, Not writable: {7}, Permissions Failed: {8}'
Expand Down
2 changes: 2 additions & 0 deletions src/gam/gamlib/glskus.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@
'product': 'Google-Chrome-Device-Management', 'aliases': ['chrome', 'cdm', 'googlechromedevicemanagement'], 'displayName': 'Google Chrome Device Management'}
}

ARCHIVABLE_SKUS = {'1010020020', '1010020025', '1010020026', '1010020027', '1010020028', 'Google-Apps-Unlimited'}

def getProductAndSKU(sku):
l_sku = sku.lower().replace('-', '').replace(' ', '').replace('"', '').replace("'", '').strip()
if l_sku.startswith('nv:'):
Expand Down

0 comments on commit a9e28e9

Please sign in to comment.