Skip to content

Commit

Permalink
feat: Add content export for dashboard and look only
Browse files Browse the repository at this point in the history
Merge pull request #108 from danieldiamond/danieldiamond/add-deploy-dashboard-and-look-content
  • Loading branch information
AdamMinton authored Feb 20, 2023
2 parents 644c0ba + eb8da0a commit 6890d04
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 11 deletions.
13 changes: 8 additions & 5 deletions looker_deployer/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,22 @@ def setup_content_subparser(subparsers):
export_subparser.add_argument("--env", required=True, help="What environment to deploy to")
export_subparser.add_argument("--ini", default=loc, help="ini file to parse for credentials")
export_subparser.add_argument("--debug", action="store_true", help="set logger to debug for more verbosity")
export_subparser.add_argument("--folders", nargs="+", required=True, help="What folders to export content from")
export_subparser.add_argument("--local-target", required=True, help="Local directory to store content")
export_content_group = export_subparser.add_argument_group()
export_content_group.add_argument("--folders", nargs="+", help="Folders to fully export")
export_content_group.add_argument("--dashboards", nargs="+", help="Dashboards to export")
export_content_group.add_argument("--looks", nargs="+", help="Looks to export")
export_subparser.set_defaults(func=deploy_content_export.main)

import_subparser.add_argument("--env", required=True, help="What environment to deploy to")
import_subparser.add_argument("--ini", default=loc, help="ini file to parse for credentials")
import_subparser.add_argument("--debug", action="store_true", help="set logger to debug for more verbosity")
import_subparser.add_argument("--recursive", action="store_true", help="Should folders deploy recursively")
import_subparser.add_argument("--target-folder", help="override the default target folder with a custom path")
content_group = import_subparser.add_mutually_exclusive_group(required=True)
content_group.add_argument("--folders", nargs="+", help="Folders to fully deploy")
content_group.add_argument("--dashboards", nargs="+", help="Dashboards to deploy")
content_group.add_argument("--looks", nargs="+", help="Looks to deploy")
import_content_group = import_subparser.add_mutually_exclusive_group(required=True)
import_content_group.add_argument("--folders", nargs="+", help="Folders to fully deploy")
import_content_group.add_argument("--dashboards", nargs="+", help="Dashboards to deploy")
import_content_group.add_argument("--looks", nargs="+", help="Looks to deploy")
import_subparser.set_defaults(func=deploy_content.main)


Expand Down
75 changes: 71 additions & 4 deletions looker_deployer/commands/deploy_content_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ def export_spaces(folder_id, env, ini, path, debug=False):
subprocess.run(gzr_command)


def export_content(content_type, content_id, env, ini, path, debug=False):
host, port, client_id, client_secret, verify_ssl = get_gzr_creds(ini, env)

gzr_command = [
"gzr",
content_type,
"cat",
content_id,
"--host",
host,
"--port",
port,
"--client-id",
client_id,
"--client-secret",
client_secret
]

# config parser returns a string - easier to parse that than convert to a bool
if verify_ssl == "False":
gzr_command.append("--no-verify-ssl")
if debug:
gzr_command.append("--debug")

# if we're running on windows we need to appropriately call the command-line arg"
if os.name == "nt":
win_exec = ["cmd.exe", "/c"]
gzr_command = win_exec + gzr_command

filename = Path(path) / f"{content_type}_{content_id}.json"
with open(filename, "w") as outfile:
subprocess.run(gzr_command, stdout=outfile)


def recurse_folders(folder_id, folder_list, sdk, debug=False):
space = sdk.space(str(folder_id))
folder_list.append(space.name)
Expand All @@ -72,8 +106,10 @@ def recurse_folders(folder_id, folder_list, sdk, debug=False):
return folder_list


def send_export(folder_ids, local_target, env, ini, sdk, debug=False):
for fid in folder_ids:
def send_export(
sdk, env, ini, local_target, folders=None, dashboards=None, looks=None, debug=False
):
for fid in folders or []:

# generate the list of folders
folder_list = []
Expand All @@ -90,6 +126,28 @@ def send_export(folder_ids, local_target, env, ini, sdk, debug=False):
# export the folder
export_spaces(fid, env, ini, str(path), debug)

for did in dashboards or []:

logger.debug("dashboard_list", extra={"dashboards": dashboards})

# create the target directory
path = Path(local_target)
path.mkdir(parents=True, exist_ok=True)

# export the dashboard
export_content("dashboard", did, env, ini, str(path), debug)

for lid in looks or []:

logger.debug("look_list", extra={"looks": looks})

# create the target directory
path = Path(local_target)
path.mkdir(parents=True, exist_ok=True)

# export the look
export_content("look", lid, env, ini, str(path), debug)


def main(args):

Expand All @@ -100,7 +158,16 @@ def main(args):

logger.info(
"Exporting content",
extra={"env": args.env, "folders": args.folders, "local_target": args.local_target}
extra={"env": args.env, "folders": args.folders, "dashboards": args.dashboards, "looks": args.looks, "local_target": args.local_target}
)
sdk = get_client(args.ini, args.env)
send_export(args.folders, args.local_target, args.env, args.ini, sdk, args.debug)
send_export(
sdk,
args.env,
args.ini,
args.local_target,
args.folders,
args.dashboards,
args.looks,
args.debug
)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@
name=NAME,
packages=["looker_deployer", "looker_deployer/commands", "looker_deployer/utils"],
entry_points={"console_scripts": ["ldeploy=looker_deployer.cli:main"]},
python_requires=">=3.6.0, <3.10",
python_requires=">=3.6.0, <3.11",
version=VERSION
)
30 changes: 29 additions & 1 deletion tests/test_deploy_content_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from unittest.mock import patch, mock_open
from pathlib import Path
import subprocess
from looker_sdk import methods
from looker_deployer.commands import deploy_content_export
Expand Down Expand Up @@ -150,5 +152,31 @@ def test_send_export(mocker):
mocker.patch("pathlib.Path.mkdir")

mocker.patch("looker_deployer.commands.deploy_content_export.export_spaces")
deploy_content_export.send_export("1", "./foo/bar", "env", "ini", "sdk", False)
deploy_content_export.send_export("sdk", "env", "ini", "./foo/bar", folders="1", debug=False)
deploy_content_export.export_spaces.assert_called_with("1", "env", "ini", "foo/bar/Shared/bosh", False)


def test_export_dashboard(mocker):
mocker.patch("looker_deployer.commands.deploy_content_export.get_gzr_creds")
deploy_content_export.get_gzr_creds.return_value = ("foobar.com", "1234", "abc", "xyz", "True")

fake_file_path = Path("foo/bar/dashboard_1.json")
with patch('looker_deployer.commands.deploy_content_export.open', mock_open()) as mocked_file:
mocker.patch("subprocess.run")
deploy_content_export.export_content("dashboard", "1", "env", "ini", "foo/bar", False)

# assert "foo/bar/dashboard_1.json" opened and on write mode 'w'
mocked_file.assert_called_once_with(fake_file_path, 'w')


def test_export_look(mocker):
mocker.patch("looker_deployer.commands.deploy_content_export.get_gzr_creds")
deploy_content_export.get_gzr_creds.return_value = ("foobar.com", "1234", "abc", "xyz", "True")

fake_file_path = Path("foo/bar/look_1.json")
with patch('looker_deployer.commands.deploy_content_export.open', mock_open()) as mocked_file:
mocker.patch("subprocess.run")
deploy_content_export.export_content("look", "1", "env", "ini", "foo/bar", False)

# assert "foo/bar/look_1.json" opened and on write mode 'w'
mocked_file.assert_called_once_with(fake_file_path, 'w')

0 comments on commit 6890d04

Please sign in to comment.