Skip to content

Commit 834b586

Browse files
committed
Add a debugging flag
If --debug is used or if DATABRICKS_DEBUGGING is set in the environment the entire contents of the http requests will be printed to stdout.
1 parent 2740846 commit 834b586

File tree

5 files changed

+71
-10
lines changed

5 files changed

+71
-10
lines changed

databricks_cli/configure/cli.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,27 @@
3232

3333
PROMPT_HOST = 'Databricks Host (should begin with https://)'
3434
PROMPT_USERNAME = 'Username'
35-
PROMPT_PASSWORD = 'Password' # NOQA
35+
PROMPT_PASSWORD = 'Password [enter stdin to read from stdin every time]' # NOQA
3636
PROMPT_TOKEN = 'Token' # NOQA
3737

3838

3939
def _configure_cli_token(profile, insecure):
4040
config = ProfileConfigProvider(profile).get_config() or DatabricksConfig.empty()
4141
host = click.prompt(PROMPT_HOST, default=config.host, type=_DbfsHost())
42-
token = click.prompt(PROMPT_TOKEN, default=config.token)
42+
token = click.prompt(PROMPT_TOKEN, default=config.token, hide_input=True)
4343
new_config = DatabricksConfig.from_token(host, token, insecure)
4444
update_and_persist_config(profile, new_config)
4545

4646

47+
def _configure_cli_stdin(profile, insecure):
48+
config = ProfileConfigProvider(profile).get_config() or DatabricksConfig.empty()
49+
host = click.prompt(PROMPT_HOST, default=config.host, type=_DbfsHost())
50+
username = click.prompt(PROMPT_USERNAME, default=config.username)
51+
password = 'stdin'
52+
new_config = DatabricksConfig.from_password(host, username, password, insecure)
53+
update_and_persist_config(profile, new_config)
54+
55+
4756
def _configure_cli_password(profile, insecure):
4857
config = ProfileConfigProvider(profile).get_config() or DatabricksConfig.empty()
4958
if config.password:
@@ -64,16 +73,19 @@ def _configure_cli_password(profile, insecure):
6473
short_help='Configures host and authentication info for the CLI.')
6574
@click.option('--token', show_default=True, is_flag=True, default=False)
6675
@click.option('--insecure', show_default=True, is_flag=True, default=None)
76+
@click.option('--stdin', show_default=True, is_flag=True, default=False)
6777
@debug_option
6878
@profile_option
69-
def configure_cli(token, insecure):
79+
def configure_cli(token, insecure, stdin):
7080
"""
7181
Configures host and authentication info for the CLI.
7282
"""
7383
profile = get_profile_from_context()
7484
insecure_str = str(insecure) if insecure is not None else None
7585
if token:
7686
_configure_cli_token(profile, insecure_str)
87+
elif stdin:
88+
_configure_cli_stdin()
7789
else:
7890
_configure_cli_password(profile, insecure_str)
7991

databricks_cli/configure/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ def callback(ctx, param, value): # NOQA
8383

8484
def _get_api_client(config, command_name=""):
8585
verify = config.insecure is None
86+
87+
if config.is_debugging and config.debugging == "1":
88+
ApiClient.enable_debug_logging()
89+
8690
if config.is_valid_with_token:
8791
return ApiClient(host=config.host, token=config.token, verify=verify,
8892
command_name=command_name)

databricks_cli/configure/provider.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2121
# See the License for the specific language governing permissions and
2222
# limitations under the License.
23-
23+
import getpass
2424
from abc import abstractmethod, ABCMeta
2525
from configparser import ConfigParser
2626
import os
@@ -33,10 +33,11 @@
3333
CONFIG_FILE_ENV_VAR = "DATABRICKS_CONFIG_FILE"
3434
HOST = 'host'
3535
USERNAME = 'username'
36-
PASSWORD = 'password' # NOQA
36+
PASSWORD = 'password' # NOQA
3737
TOKEN = 'token'
3838
INSECURE = 'insecure'
3939
DEFAULT_SECTION = 'DEFAULT'
40+
DEBUG = 'debug'
4041

4142
# User-provided override for the DatabricksConfigProvider
4243
_config_provider = None
@@ -238,7 +239,11 @@ def get_config(self):
238239
password = os.environ.get('DATABRICKS_PASSWORD')
239240
token = os.environ.get('DATABRICKS_TOKEN')
240241
insecure = os.environ.get('DATABRICKS_INSECURE')
241-
config = DatabricksConfig(host, username, password, token, insecure)
242+
debugging = os.environ.get('DATABRICKS_DEBUGGING')
243+
if debugging is None:
244+
debugging = 0
245+
246+
config = DatabricksConfig(host, username, password, token, insecure, debugging=debugging)
242247
if config.is_valid:
243248
return config
244249
return None
@@ -256,19 +261,30 @@ def get_config(self):
256261
password = _get_option_if_exists(raw_config, self.profile, PASSWORD)
257262
token = _get_option_if_exists(raw_config, self.profile, TOKEN)
258263
insecure = _get_option_if_exists(raw_config, self.profile, INSECURE)
259-
config = DatabricksConfig(host, username, password, token, insecure)
264+
debugging = _get_option_if_exists(raw_config, self.profile, DEBUG)
265+
if debugging is None:
266+
debugging = 0
267+
268+
config = DatabricksConfig(host, username, password, token, insecure, debugging=debugging)
260269
if config.is_valid:
261270
return config
262271
return None
263272

264273

265274
class DatabricksConfig(object):
266-
def __init__(self, host, username, password, token, insecure): # noqa
275+
def __init__(self, host, username, password, token, insecure, debugging=0): # noqa
267276
self.host = host
268277
self.username = username
269-
self.password = password
278+
279+
if self.password == 'stdin':
280+
self.password = getpass.getpass("Password to connect to databricks at [" + self.host + "]: ")
281+
else:
282+
self.password = password
283+
270284
self.token = token
271285
self.insecure = insecure
286+
self.debugging = debugging
287+
272288

273289
@classmethod
274290
def from_token(cls, host, token, insecure=None):
@@ -293,3 +309,7 @@ def is_valid_with_password(self):
293309
@property
294310
def is_valid(self):
295311
return self.is_valid_with_token or self.is_valid_with_password
312+
313+
@property
314+
def is_debugging(self):
315+
return self.debugging

databricks_cli/jobs/api.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ def create_job(self, json, headers=None):
3131
return self.client.client.perform_query('POST', '/jobs/create', data=json, headers=headers)
3232

3333
def list_jobs(self, headers=None):
34-
return self.client.list_jobs(headers=headers)
34+
resp = self.client.list_jobs(headers=headers)
35+
if 'jobs' not in resp:
36+
resp['jobs'] = []
37+
return resp
3538

3639
def delete_job(self, job_id, headers=None):
3740
return self.client.delete_job(job_id, headers=headers)

databricks_cli/sdk/api_client.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import base64
3232
import json
33+
import logging
3334
import warnings
3435
import requests
3536
import ssl
@@ -129,6 +130,27 @@ def perform_query(self, method, path, data = {}, headers = None):
129130
raise requests.exceptions.HTTPError(message, response=e.response)
130131
return resp.json()
131132

133+
@classmethod
134+
def enable_debug_logging(cls):
135+
# These two lines enable debugging at httplib level (requests->urllib3->http.client)
136+
# You will see the REQUEST, including HEADERS and DATA, and RESPONSE with HEADERS but without DATA.
137+
# The only thing missing will be the response.body which is not logged.
138+
try:
139+
import http.client as http_client
140+
except ImportError:
141+
# Python 2
142+
import httplib as http_client
143+
144+
print ("HTTP debugging enabled")
145+
http_client.HTTPConnection.debuglevel = 1
146+
147+
# You must initialize logging, otherwise you'll not see debug output.
148+
logging.basicConfig()
149+
logging.getLogger().setLevel(logging.DEBUG)
150+
requests_log = logging.getLogger("requests.packages.urllib3")
151+
requests_log.setLevel(logging.DEBUG)
152+
requests_log.propagate = True
153+
132154

133155
def _translate_boolean_to_query_param(value):
134156
assert not isinstance(value, list), 'GET parameters cannot pass list of objects'

0 commit comments

Comments
 (0)