How to Move a Look to a New Looker Instance

Knowledge Drop

Last tested: Jun 25, 2020
 

You can find the Python script in this repository.

The Easy Way

Use Looker Deployer

The Problem

Unlike LookML objects such as models and views files, Looks are not version control (does not live in your Git repository); thus, moving them from one instance to another requires other approaches.

To illustrate, imagine that your organization has bought a new instance and you want to move, for example, a LookML project from the old instance to the new one. You were able to create a connection to the database, set up the project in the new instance by downloading the LookML files from your Git Repo. In other words, you have all models, views, explores, LookML-Dashboards files up and running in the new instance but now you need to move the Looks from the old instance to the new one.

A Solution

One of the solutions is to use Looker's API. In this article, we're going to use the Python SDK to move a Look from one instance to another.

Let's call the current instance old_instance and the new one new_instance.

Step 1: Create .ini files

The first step is to create two .ini files that will have our API credentials and used to configure the SDK client.

For this implementation, we have a local.ini file that contains the API credentials and base URL of the new instance, and a dcl.ini file which contains the credentials of the old instance.

Step 2: Import Python libraries, create functions and configure the SDK clients

We start by importing the libraries and define two functions that we'll use to reach out our end goal.

import os

import json

import configparser

from looker_sdk import client, models

config = configparser.ConfigParser()

config.read('dcl.ini')

The first function runs a shell command to hit the login endpoint then return the access token that will be used in the second function.

Once we have the access token we can make a call to the Get Look endpoint then extract the visualization configuration. This is done in the second function.

In both functions, we're hitting the API endpoints using command line codes. We are doing this because the visualization configuration returned by the SDK is a little bit different thus leading to some inconsistent results in terms of visualization.

def get_access_token():

client_id = config['Looker']['client_id']

client_secret = config['Looker']['client_secret']

base_url = config['Looker']['base_url']

# Get access token

token = os.popen(f'curl -X POST "{base_url}/login?client_id={client_id}&client_secret={client_secret}"')

token = token.readlines()

token = token[0].split(':')

token = token[1].split(',')

token = token[0].replace('"', '')

return token

def get_viz_config(look_id):

token = get_access_token()

base_url = config['Looker']['base_url']

look = os.popen(f'curl -i -H "Authorization: token {token}" {base_url}/api/3.1/looks/{look_id}')

look = look.readlines()

look_data = json.loads(look[13])

viz_config = look_data.get('query')

viz_config = viz_config.get('vis_config')

return viz_config

Once we have our functions set we're going to create a variable old_instance_viz which will hold the visualization configuration that we'll use later on.

We are moving a Look which has a look_id = 1830

old_instance_viz = get_viz_config(look_id=1830)

Before moving to the next step, we need to configure the SDK for both instances:

sdk_old_instance = client.setup("dcl.ini")

sdk_new_instance = client.setup("local.ini")

Step 3: Get the Look to move

In this step, we're going to get the Look that needs to be moved by making a call to the Get Look endpoint. We are going to pass in the look_id only so that we'll get the detailed information about the Look and its associated Query.

# Get the Look from DCL instance

old_look = sdk_old_instance.look(look_id=1830)

old_query = old_look.query

Step 4: Create a Folder in the new instance

We want to make things easier and organized for our users so that when they want to find the Look that was moved from the old instance, they can go to a specific folder called Looks moved with API in the new instance. To create this folder under the user's main folder, we need to know who created the Look in the old instance, find their user_id and space_id (folder id) in the new instance, then create a the new sub folder.

# Get the user who created the ID

old_user_id = old_look.user

old_user_info = sdk_old_instance.user(user_id=old_user_id.id)

## Find user in Local instance based on email:

cred = old_user_info.email

new_user = sdk_new_instance.user_for_credential(credential_type='email', credential_id=cred)

# User's info in New instance

user_id = new_user.id

folder_id = new_user.personal_space_id

# Create Folder in new instance

to_new_folder = 'Looks moved with API'

try:

folder = models.WriteFolder(name=to_new_folder, parent_id=folder_id)

_ = sdk_new_instance.create_folder(body=folder)

except:

pass

# Find the ID of the created folder

new_folder = sdk_new_instance.search_folders(name=to_new_folder)

new_folder_id = new_folder[0].id

Endpoints used in this step:

Get User by Id which returns the information about the user who created the Look.

Get User by Credential Id which returns the information of our user in the new Instance based on their email.

Create Folder to create the folder in the new instance.

Notice that we're assigning the result of the create folder call to the _ variable because the create folder endpoint returns some data after creating the folder. We are not going to use these data again and we also don't want to print it in the terminal.

Search Folders to find the info of the subfolder in the new instance and extract its ID that will be used later.

Step 5: Create a Query in the new instance

To create a Look via the API we need a query_id and for this reason, we're going to create a Query by making a call to the Create Query endpoint. This logic is similar to what we do in Looker UI; we start by creating an explore which generates a query_id then we save this explore as a Look.

We start by creating the body by passing all the information of the Look saved in the old_query variable.

It's here where we'll use the info stored in the old_instance_viz variable.

# Build Query's body

create_query = models.WriteQuery(model= old_query.model, view = old_query.view, fields = old_query.fields,\\

pivots= old_query.pivots, fill_fields= old_query.fill_fields, filters = old_query.filters,\\

filter_expression = old_query.filter_expression, sorts = old_query.sorts, limit = old_query.limit,\\

column_limit = old_query.column_limit, total = old_query.total, row_total= old_query.row_total,\\

subtotals = old_query.subtotals, vis_config = old_instance_viz, filter_config = old_query.filter_config,\\

visible_ui_sections = old_query.visible_ui_sections, dynamic_fields = old_query.dynamic_fields)

Then we make the call to the endpoint using:

# Get new query's info

new_query = sdk_new_instance.create_query(body=create_query)

Step 6: Create the Look

We have all we need to create the Look in the new instance. We'll make a call to the Create Look endpoint.

# Build Look's body

look_body = models.WriteLookWithQuery(title=old_look.title, is_run_on_load=True, \\

query_id=new_query.id, space_id=new_folder_id, \\

user_id=user_id, query=create_query)

Now we can make the call that will create the Look in the new instance:

# Create Look

_ = sdk_new_instance.create_look(body=look_body)

print("Congratulation!!! Your Look is in the new instance now.")

This content is subject to limited support.                

Version history
Last update:
‎07-07-2021 01:52 PM
Updated by: