Skip to content

Commit 1195c7f

Browse files
authored
Releasing version 3.22.4
Releasing version 3.22.4
2 parents 86ce649 + 6c6a750 commit 1195c7f

File tree

18 files changed

+828
-171
lines changed

18 files changed

+828
-171
lines changed

CHANGELOG.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,50 @@ All notable changes to this project will be documented in this file.
66

77
The format is based on `Keep a Changelog <http://keepachangelog.com/>`__.
88

9+
3.22.4 - 2023-01-31
10+
--------------------
11+
Added
12+
~~~~~
13+
14+
* Support for new optional parameters for ExaCC, vault secret, and tool details in the Database service
15+
16+
* ``oci db autonomous-database create --compute-count --compute-model --secret-id --secret-version-number --db-tools-details``
17+
* ``oci db autonomous-database create-adb-cross-region-data-guard-details --compute-count --compute-model --secret-id --secret-version-number --db-tools-details``
18+
* ``oci db autonomous-database create-from-backup-id --compute-count --compute-model --secret-id --secret-version-number --db-tools-details``
19+
* ``oci db autonomous-database create-from-backup-timestamp --compute-count --compute-model --secret-id --secret-version-number --db-tools-details``
20+
* ``oci db autonomous-database create-from-clone --compute-count --compute-model --secret-id --secret-version-number --db-tools-details``
21+
* ``oci db autonomous-database create-refreshable-clone --compute-count --compute-model --secret-id --secret-version-number --db-tools-details``
22+
* ``oci db autonomous-database update --compute-count --secret-id --secret-version-number --db-tools-details``
23+
* ``oci db autonomous-vm-cluster create --compute-model``
24+
* ``oci db cloud-autonomous-vm-cluster create --compute-model``
25+
26+
* Support for new optional parameters enabling role-based access control in the Opensearch service
27+
28+
* ``oci opensearch cluster create --security-mode --security-master-user-name --security-master-user-password-hash``
29+
* ``oci opensearch cluster update --security-mode --security-master-user-name --security-master-user-password-hash``
30+
31+
* Devops service
32+
33+
* Support for new commands
34+
35+
* ``oci devops deploy-stage create-shell-stage``
36+
* ``oci devops deploy-stage update-shell-stage``
37+
38+
* Support for new artifact type COMMAND_SPEC for existing parameter ``--artifact-type``
39+
40+
* ``oci devops deploy-artifact update --artifact-type command_spec``
41+
* ``oci devops deploy-artifact create-generic-artifact --artifact-type command_spec``
42+
* ``oci devops deploy-artifact create-inline-artifact --artifact-type command_spec``
43+
* ``oci devops deploy-artifact update-generic-artifact --artifact-type command_spec``
44+
* ``oci devops deploy-artifact update-inline-artifact --artifact-type command_spec``
45+
46+
Fixed
47+
~~~~~
48+
49+
* Fixed reading from and writing to default config (~/.oci/config) when importing authentication session
50+
51+
* ``oci session import``
52+
953
3.22.3 - 2023-01-24
1054
--------------------
1155
Added

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Jinja2==3.0.3
1414
jmespath==0.10.0
1515
ndg-httpsclient==0.4.2
1616
mock==2.0.0
17-
oci==2.90.3
17+
oci==2.90.4
1818
packaging==20.2
1919
pluggy==0.13.0
2020
py==1.10.0

scripts/examples/project_o/README.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ Public Subnet VLKn:US-ASHBURN-AD-1 AVAILABLE 10.0.0.0/24 sales
6666
- support [complex type] parameters where a list of OCIDs is expected
6767
- comma-separated resource names are converted to a JSON list
6868
- simplify [datetime] parameters
69-
- ``--start-time **today**`` beginning (midnight) of current day (UTC)
70-
- ``--start-time **today-36h**`` - the day before yesterday at Noon
71-
- ``--end-time **now**`` - current day+time (UTC)
69+
- ``--start-time today`` beginning (midnight) of current day (UTC)
70+
- ``--start-time today-36h`` - the day before yesterday at Noon
71+
- ``--end-time now`` - current day+time (UTC)
7272
- output in *table, text, csv* or *JSON* format. Format is based on your field separator
7373
- *table:* `-o display#lifecycle` or `-o 'display|lifecycle'`
7474
- *text:* `-o display/lifecycle` - displays one field per line
@@ -87,14 +87,25 @@ Public Subnet VLKn:US-ASHBURN-AD-1 AVAILABLE 10.0.0.0/24 sales
8787
- *id* in `-o name#id` selects the id (OCID of *this* resource) but not *image-id* or other ids in the same record
8888
- quick lookup of full OCIDs from *resource name* or partial OCID
8989
- `o ocids compartment` *instantly* shows the full OCIDs for all compartments
90-
- `o ocid sales/bastion` *instantly* shows the full OCIDs for all compartments
90+
- `o ocid sales/bastion` *instantly* shows the full OCIDs for the specified compartment
9191

92-
#### New features in version 1.3 (2022-12-15)
93-
- get paginated results with `o <repeat-last-command> -page next`
94-
- take JSON input from a file and format output with `o`
95-
- `o -i data.json -o name#id#date`
92+
#### New in version 1.3 (2022-12-15)
93+
- get next page of results with `o <repeat-last-command> -page next`
9694
- select child fields from complex output with `-o key.subkey`
97-
- note: some fields are dicts or lists that only present well in "text" format
95+
- first use `o -o / <command> .` to see all available data fields
96+
- then rerun with desired `-o key#key.subkey` list.
97+
- save `oci` output (or `o -o json` output) to a file, then format with `o` - useful for getting the format just right
98+
- `o -o json list compute instances > data.json`
99+
- `o -i data.json -o name#id#date`
100+
101+
#### New in version 1.4 (2023-01-20)
102+
- replace compartment names with OCIDs in:
103+
- `oci search resource structured-search --query-text <text>`
104+
- `oci logging-search search-logs --search-query <text>`
105+
- easier output formatting. Braces are optional, allow ":-" instead of ":>" for right-justify
106+
- `o -o id:-.10#name:6#create:.10 comp inst list`
107+
- table output with right-most 10 characters of `id`, `display-name` in 6 (or more) characters, and first 10 characters of `time-created`
108+
98109

99110
## Installation
100111

scripts/examples/project_o/o

Lines changed: 99 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import os
2020
import fcntl
2121
import errno
2222
import datetime
23-
VERSION = "1.3"
24-
UPDATED = "2023-01-04"
23+
VERSION = "1.4"
24+
UPDATED = "2023-01-20"
2525

2626
# ==============================================================================
2727
# Global variables
@@ -53,7 +53,8 @@ default_out_spec = 'name{:.30}#shape#cidr-block#prohibit-public{:5.5}' \
5353
'#direction#destination' \
5454
'#ip-address#public-ip#private-ip' \
5555
'#vnic-id#desc{:.40}' \
56-
'#access-uri#storage-tier'
56+
'#access-uri#storage-tier' \
57+
'#token'
5758

5859
matches = [] # list of commands that match user input
5960
best_match = None # matches[best_match] is the closest match
@@ -860,6 +861,9 @@ def get_matching_ocid(option, value):
860861
opt_type = 'rovernode'
861862
elif opt_type == 'authtoken':
862863
opt_type = 'credential'
864+
elif opt_type == 'zonenameor':
865+
opt_type = 'dns-zone'
866+
# print('HERE opt_type', opt_type)
863867

864868
matches = [item for k, item in ocid.items() if
865869
type_match(opt_type, item['type'])
@@ -941,14 +945,30 @@ def value_parameter(option, value):
941945
return datetime_parameter(value)
942946

943947
# Special help with log-search --search-query "search comp1 comp2 | ..."
944-
# Substitute compartment ocid for one or more values.
948+
# Substitute "ocid1.compartment..." for one or more values.
945949
if option == '--search-query':
946950
m = re.search(r'search ([^|]+)', value)
947951
if m:
948-
for v in m.group(1).split():
949-
o = get_matching_ocid('compartment', v)
950-
if o != v:
951-
value = re.sub(v, '"' + o + '"', value)
952+
for comp in m.group(1).split():
953+
c = comp
954+
if c.startswith('"'):
955+
c = comp[1:-1]
956+
o = get_matching_ocid('compartment', c)
957+
if o != c:
958+
value = re.sub(comp, '"' + o + '"', value)
959+
960+
# Special help with structured-search --search-query "where compartmentId = ocid"
961+
if option == '--query-text':
962+
match = re.findall(r"(c\w*) *= *('*\w+'*)", value, flags=re.IGNORECASE)
963+
for (m, spec) in match:
964+
if m.lower() == 'compartmentid'[:len(m)]:
965+
if m.lower() != 'compartmentid':
966+
value = re.sub(r'\b' + m + r'\b', 'compartmentId', value)
967+
if spec.startswith("'"):
968+
spec = spec[1:-1]
969+
o = get_matching_ocid('compartment', spec)
970+
if o != spec:
971+
value = re.sub(spec, "'" + o + "'", value)
952972

953973
return value
954974

@@ -1003,9 +1023,13 @@ def get_fields_from(spec, keynames):
10031023
s, fmt = sf, '{}'
10041024
if s == '.':
10051025
s = ''
1006-
m = re.search('(.*)({.*})', s)
1026+
m = re.search('([^:{]+)(.*)', s)
10071027
if m:
10081028
s, fmt = m.group(1), m.group(2)
1029+
if not fmt.startswith('{'):
1030+
fmt = '{' + fmt + '}'
1031+
if fmt.startswith('{:r') or fmt.startswith('{:-'):
1032+
fmt = '{:>' + fmt[3:]
10091033
if s in sorted(keynames): # exact keyname match
10101034
fields.append(s)
10111035
column[s] = {'format': fmt, 'offset': 0, 'minwidth': len(s)}
@@ -1017,26 +1041,25 @@ def get_fields_from(spec, keynames):
10171041
if (user_out_spec == default_out_spec and (
10181042
k == 'quota-names'
10191043
or s == 'size' and 'resize' in k
1020-
or s == 'id' and 'bandwidth' in k)):
1044+
or s == 'id' and 'bandwidth' in k
1045+
or s == 'id' and 'identity' in k)):
10211046
continue
10221047
kf = k.split('.')
10231048
# sub-key partial matches must partial-match: key.subkey
10241049
if ((k not in fields)
1025-
and ((s in k and '.' not in k)
1050+
and ((s.lower() in k.lower() and '.' not in k)
10261051
or ('.' in s and '.' in k
1027-
and (sf[-1] in kf[-1])
1028-
and (sf[-2] in kf[-2])))):
1052+
and (sf[-1].lower() in kf[-1].lower())
1053+
and (sf[-2].lower() in kf[-2].lower())))):
10291054
fields.append(k)
10301055
column[k] = {'format': fmt, 'offset': 0, 'minwidth': len(s)}
10311056
if debug: print('{:>30.30}'.format(s), '->', k) # noqa: E701
1032-
# Partial match at top level key skips lower level matches.
1033-
# if s and '.' not in k or k.endswith('.'+s):
1034-
# break
10351057

10361058
if len(fields) == 0:
10371059
if user_out_spec != default_out_spec:
10381060
print(bold("no matching output fields: " + spec), file=sys.stderr)
10391061
return get_fields_from("/", keynames)
1062+
if debug: print("COLUMN:", column) # noqa: E701
10401063
return fields, sep
10411064

10421065
# ==============================================================================
@@ -1087,8 +1110,12 @@ def show_column_headers(out_fields, sep):
10871110
if sep == '|':
10881111
for k in out_fields:
10891112
# print(bold(column[k]['format'].format(k)), end=' ', file=sys.stderr)
1090-
print(bold(column[k]['format'].format(k.split(".")[-1])),
1091-
end=' ', file=sys.stderr)
1113+
try:
1114+
print(bold(column[k]['format'].format(k.split(".")[-1])),
1115+
end=' ', file=sys.stderr)
1116+
except ValueError:
1117+
print(bold("bad format: " + k + column[k]['format']))
1118+
column[k]['format'] = '{}'
10921119
print('', file=sys.stderr)
10931120
elif sep != '/':
10941121
if sep == ',':
@@ -1099,35 +1126,45 @@ def show_column_headers(out_fields, sep):
10991126
# ==============================================================================
11001127

11011128

1129+
def jdump_item(item):
1130+
"""Remove json decorations, empty lines from json.dumps output"""
1131+
1132+
return (re.sub(r'(?m)"\s*$|( *)"', r'\1', # remove outer double-quotes
1133+
# remove closing braces and trailing newline
1134+
re.sub(r'(?m)[\[\]{},]+$', '', # noqa: E128
1135+
# noqa: E128 remove braces at beginning of lines, empty lines
1136+
re.sub(r'(?m)^[\s{}[\],]+\n', '', # noqa: E128
1137+
# noqa: E128 change key: [ value ] -> key: value
1138+
re.sub(r': \[\s+("[^"]*")\s+]', r': \1', # noqa: E128
1139+
json.dumps(item, indent=2)))))) # noqa: E128
1140+
1141+
# ==============================================================================
1142+
1143+
11021144
def show_item(item, fields, sep):
11031145
"""Report result in user specified -o format."""
11041146

11051147
out = []
11061148
for field in fields:
11071149
value = ''
1108-
# print(json.dumps(item[f[0]][f[1]], indent=4))
11091150
if field in item:
11101151
value = str(item[field])
11111152
else:
11121153
# field contains "." - need to look deeper
11131154
f = field.split('.')
11141155
if len(f) > 1:
11151156
if f[-1] in item[f[0]]:
1116-
# remove json decorations, remove empty lines
1117-
value = re.sub(r'[{}\'"[\]]', '',
1118-
re.sub(r'(?m)^[ {},[\]]+\n', '',
1119-
json.dumps(item[f[0]][f[1]], indent=4)))
1157+
value = jdump_item(item[f[0]][f[1]])
11201158
else:
11211159
if type(item[f[0]]) is list:
1122-
subitem = item[f[0]]
1160+
subitem = jdump_item(item[f[0]])
11231161
else:
11241162
subitem = item[f[0]][f[1]] if f[1] in item[f[0]] else None
1163+
if type(subitem) is dict and f[-1] in subitem:
1164+
value = jdump_item(subitem[f[-1]])
11251165
if type(subitem) is list and f[-1] in subitem[0]:
1126-
# remove json decorations, remove empty lines
11271166
s = [' ' + v[f[-1]] for v in subitem if f[-1] in v]
1128-
value = re.sub(r'[{}\'"[\]]', '',
1129-
re.sub(r'(?m)^[ {},[\]]+\n?', '',
1130-
json.dumps(s, indent=4)))
1167+
value = jdump_item(s)
11311168

11321169
if field not in ('id', 'identifier') and value in ocid and not ocids_in_output:
11331170
value = ocid[value]['alias']
@@ -1136,10 +1173,7 @@ def show_item(item, fields, sep):
11361173

11371174
if column[field]['format'] == '{}' and sep != '|':
11381175
if field in item:
1139-
out.append(re.sub(r'[{}\'"[\]]', '',
1140-
# re.sub(r'(?m)^[ {},[\]]+\n?', '',
1141-
re.sub(r'(?m)^[ {},[\]]+\n', '',
1142-
json.dumps(item[field], indent=4))))
1176+
out.append(jdump_item(item[field]))
11431177
else:
11441178
out.append(value)
11451179
else:
@@ -1152,22 +1186,20 @@ def show_item(item, fields, sep):
11521186
for k, value in zip(fields, out):
11531187
# Wrap long lines
11541188
if k == 'access-uri':
1155-
print(column['keyfmt'].format(k), ' ', value)
1189+
print(column['keyfmt'].format(k) + ' ' + value)
1190+
elif '\n' in value:
1191+
# value = re.sub(r'(,){0,1}\n ', '\n' + ' ' * (maxkeylen + 3), value)
1192+
value = re.sub(r'\n ', '\n' + ' ' * (maxkeylen + 3), value)
1193+
value = re.sub(r'$\n', '', value)
1194+
value = re.sub(r'^ ', '', re.sub('\n ', '\n', value))
1195+
print(column['keyfmt'].format(k) + ' ' + value)
11561196
else:
1157-
# print(value)
1158-
if '\n' in value:
1159-
# value = re.sub(r'(,){0,1}\n', '\n' + ' ' * (maxkeylen + 3), value) #.strip()
1160-
value = re.sub(r'(,){0,1}\n ', '\n ' + ' ' * (maxkeylen + 3), value)
1161-
value = re.sub(r'$\n', '', value)
1162-
value = re.sub(r'^ ', '', re.sub('\n ', '\n', value))
1163-
print(column['keyfmt'].format(k), ' ', value)
1164-
else:
1165-
print(column['keyfmt'].format(k), ' ',
1166-
textwrap.fill(value,
1167-
subsequent_indent=indent,
1168-
break_on_hyphens=True,
1169-
break_long_words=True,
1170-
width=wrap - maxkeylen - 3))
1197+
print(column['keyfmt'].format(k) + ' '
1198+
+ textwrap.fill(value,
1199+
subsequent_indent=indent,
1200+
break_on_hyphens=True,
1201+
break_long_words=True,
1202+
width=wrap - maxkeylen - 3))
11711203
if len(fields) > 1:
11721204
print('')
11731205

@@ -1215,10 +1247,17 @@ def output(jsonOut):
12151247
if type(jsonOut['data']) is list:
12161248
results = jsonOut['data']
12171249
elif type(jsonOut['data']) is dict:
1218-
if 'items' in jsonOut['data'] and type(jsonOut['data']['items']) is list:
1219-
results = jsonOut['data']['items']
1220-
else:
1221-
results = [jsonOut['data']]
1250+
try:
1251+
if 'items' in jsonOut['data'] and type(jsonOut['data']['items']) is list:
1252+
results = jsonOut['data']['items']
1253+
# logging-search search-logs results:
1254+
elif 'results' in jsonOut['data'] and type(jsonOut['data']['results']) is list\
1255+
and 'logContent' in jsonOut['data']['results'][0]['data']:
1256+
results = [i['data']['logContent']['data'] for i in jsonOut['data']['results']]
1257+
else:
1258+
results = [jsonOut['data']]
1259+
except (KeyError, IndexError):
1260+
results = [jsonOut]
12221261
else:
12231262
results = [jsonOut] # sloppy
12241263

@@ -1523,6 +1562,8 @@ def prune(argv):
15231562
n += prune_this(i)
15241563
if item['id'] in ocid:
15251564
del ocid[item['id']]
1565+
elif item['type'] == 'availabilitydomain' and item['name'] in ocid:
1566+
del ocid[item['name']]
15261567
return n + 1
15271568

15281569
# ==========================================================================
@@ -1972,10 +2013,17 @@ except subprocess.SubprocessError as err:
19722013

19732014
flags = fcntl.fcntl(cli.stdout, fcntl.F_GETFL)
19742015
fcntl.fcntl(cli.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
2016+
flags = fcntl.fcntl(cli.stderr, fcntl.F_GETFL)
2017+
fcntl.fcntl(cli.stderr, fcntl.F_SETFL, flags | os.O_NONBLOCK)
19752018

19762019
# Read output from cli - show non-JSON on stdout
19772020
JSONstdout = ''
19782021
while True:
2022+
stderr = cli.stderr.readline()
2023+
returncode = cli.poll()
2024+
if stderr:
2025+
print(bold(stderr), end='', flush=True)
2026+
19792027
stdout = cli.stdout.readline()
19802028
returncode = cli.poll()
19812029
if stdout == '' and returncode is not None:

0 commit comments

Comments
 (0)