Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Önemli
Bu özellik Genel Önizleme aşamasındadır. Önizlemeler sayfasında önizleme kaydını onaylayabilirsiniz. Bkz. Azure Databricks önizlemelerini yönetme.
Bu sayfada dış kullanıcılar için eklemenin nasıl çalıştığı, azure Databricks çalışma alanınızı ekli panoların güvenli paylaşımı için yapılandırma ve başlamak için örnek uygulamaların nasıl kullanılacağı açıklanmaktadır. Dış kullanıcılar için ekleme, katıştırılmış panoların kimliğini doğrulamak ve erişimi yetkilendirmek için bir hizmet sorumlusu ve kapsamlı erişim belirteçleri kullanır. Bu yaklaşım, bu kullanıcılar için Azure Databricks hesapları sağlamadan panoları kuruluşunuzun dışındaki iş ortakları ve müşteriler gibi görüntüleyicilerle paylaşmanızı sağlar.
Kuruluşunuzdaki kullanıcılar için pano ekleme de dahil olmak üzere diğer ekleme seçenekleri hakkında bilgi edinmek için bkz. Pano ekleme.
Dış kullanıcılar için ekleme nasıl çalışır?
Aşağıdaki diyagram ve numaralandırılmış adımlar, dış kullanıcılar için bir pano eklediğinizde kullanıcıların kimliğinin nasıl doğrulandığını ve panoların kullanıcı kapsamlı sonuçlarla nasıl doldurulduğunu açıklar.
- Kullanıcı kimlik doğrulaması ve isteği: Kullanıcı uygulamanızda oturum açar. Uygulamanızın ön ucu, pano erişim belirteci için sunucunuza kimliği doğrulanmış bir istek gönderir.
-
Hizmet sorumlusu kimlik doğrulaması: Sunucunuz, Databricks sunucusundan bir OAuth belirteci istemek ve almak için hizmet sorumlusu gizli dizisini kullanır. Bu, Azure Databricks'in hizmet sorumlusu adına erişimi olan tüm pano API'lerini çağırabilen geniş kapsamlı bir belirteçtir. Sunucunuz, ve gibi
/tokeninfoexternal_viewer_idtemel kullanıcı bilgilerini geçirerek bu belirteci kullanarak uç noktayı çağırırexternal_value. Bkz. Panoları tek tek kullanıcılara güvenli bir şekilde sunma. -
Kullanıcı kapsamlı belirteç oluşturma: Sunucunuz, uç noktadan ve Databricks OpenID Connect (OIDC) uç noktasından gelen
/tokeninfoyanıtı kullanarak, iletmiş olduğunuz kullanıcı bilgilerini kodlayan sıkı kapsamlı yeni bir belirteç oluşturur. -
Pano işleme ve veri filtreleme: Uygulama sayfasından örnek oluşturulur
DatabricksDashboard@databricks/aibi-clientve oluşturma sırasında kullanıcı kapsamlı belirteci geçirir. Pano, kullanıcının bağlamıyla işlenir. Bu belirteç erişimi yetkiler, ileexternal_viewer_iddenetimi destekler ve veri filtreleme için taşırexternal_value. Pano veri kümelerindeki sorgular, kullanıcı başına filtre uygulamak için başvurabilir__aibi_external_valueve her görüntüleyicinin yalnızca görüntülemesine izin verilen verileri görmesini sağlar.
Panoları tek tek kullanıcılara güvenli bir şekilde sunma
Uygulama sunucunuzu, her kullanıcı için kendi external_viewer_idtabanlı benzersiz bir kullanıcı kapsamlı belirteci oluşturacak şekilde yapılandırın. Bu, denetim günlükleri aracılığıyla pano görünümlerini ve kullanımını izlemenizi sağlar.
external_viewer_id, pano veri kümelerinde kullanılan SQL sorgularına eklenebilen genel bir değişken işlevi gören bir external_valueile eşleştirilir. Bu, her kullanıcı için panoda görüntülenen verileri filtrelemenizi sağlar.
external_viewer_id pano denetim günlüklerinize geçirilir ve kişisel bilgileri içermemelidir. Bu değer kullanıcı başına benzersiz olmalıdır.
external_value sorgu işlemede kullanılır ve kişisel bilgileri içerebilir .
Aşağıdaki örnekte, dış değerin veri kümesi sorgularında filtre olarak nasıl kullanılacağı gösterilmektedir:
SELECT *
FROM sales
WHERE region = __aibi_external_value
Kuruluma genel bakış
Bu bölüm, bir panoyu dış konuma eklemek üzere ayarlamak için gerçekleştirmeniz gereken adımlara yönelik üst düzey kavramsal bir genel bakış içerir.
Dış uygulamaya pano eklemek için önce Azure Databricks'te bir hizmet sorumlusu oluşturup bir gizli dizi oluşturursunuz. Hizmet sorumlusuna panoya ve temel alınan verilere okuma erişimi verilmelidir. Sunucunuz hizmet sorumlusu adına pano API'lerine erişebilen bir belirteç almak için hizmet sorumlusu gizli dizisini kullanır. Bu belirteçle sunucu, ve /tokeninfo değerleri de dahil olmak üzere external_value temel kullanıcı profili bilgilerini döndüren openID Connect (OIDC) uç noktası olan API uç noktasını çağırırexternal_viewer_id. Bu değerler istekleri tek tek kullanıcılarla ilişkilendirmenize olanak sağlar.
Sunucunuz, hizmet sorumlusundan alınan belirteci kullanarak panoya erişen belirli bir kullanıcı kapsamında yeni bir belirteç oluşturur. Bu kullanıcı kapsamlı belirteç, uygulamanın kitaplıktan DatabricksDashboard nesnenin örneğini @databricks/aibi-client oluşturduğu uygulama sayfasına geçirilir. Belirteç, denetimi destekleyen kullanıcıya özgü bilgileri taşır ve her kullanıcının yalnızca erişim yetkisine sahip olduğu verileri görmesi için filtrelemeyi zorlar. Kullanıcının bakış açısından, uygulamada oturum açmak otomatik olarak eklenmiş panoya doğru veri görünürlüğüyle erişim sağlar.
Hız sınırları ve performansla ilgili dikkat edilmesi gerekenler
Dış ekleme, saniyede 20 pano yükü hız sınırına sahiptir. Aynı anda 20'den fazla pano açabilirsiniz, ancak 20'den fazla pano aynı anda yüklenmeye başlanmaz.
Önkoşullar
Dış ekleme uygulamak için aşağıdaki önkoşulları karşıladığınızdan emin olun:
- Yayımlanmış bir panoda en azından CAN MANAGE izinlerine sahip olmanız gerekir. Bkz . Öğretici: Gerekirse örnek panoları hızla oluşturmak ve yayımlamak için örnek panoları kullanma.
- Databricks CLI sürüm 0.205 veya üzeri yüklü olmalıdır. Yönergeler için bkz. Databricks CLI'yı yükleme veya güncelleştirme . OAuth kimlik doğrulamasını yapılandırmak ve kullanmak için bkz. OAuth kullanıcıdan makineye (U2M) kimlik doğrulaması.
- Çalışma alanı yöneticisi, eklenmiş panoyu barındırabilecek onaylı etki alanlarının listesini tanımlamalıdır. Yönergeler için bkz. Pano eklemeyi yönetme .
- Ekli panonuzu barındırmak için bir dış uygulama. Kendi uygulamanızı veya sağlanan örnek uygulamaları kullanabilirsiniz.
1. Adım: Hizmet sorumlusu oluşturma
Azure Databricks içindeki dış uygulamanızın kimliği olarak hareket etmek için bir hizmet sorumlusu oluşturun. Bu hizmet sorumlusu, uygulamanız adına isteklerin kimliğini doğrular.
Hizmet sorumlusu oluşturmak için:
- Çalışma alanı yöneticisi olarak Azure Databricks çalışma alanında oturum açın.
- Azure Databricks çalışma alanının üst çubuğunda kullanıcı adınıza tıklayın ve Ayarlar'ı seçin.
- Sol bölmede Kimlik ve erişim'e tıklayın.
- Hizmet sorumluları yanındaki Yönet seçeneğine tıklayın.
- Hizmet sorumlusu ekle'ye tıklayın.
- Yeni ekle'ye tıklayın.
- Hizmet sorumlusu için açıklayıcı bir ad girin.
- Ekle'yi tıklatın.
- Hizmet sorumluları listeleme sayfasından yeni oluşturduğunuz hizmet sorumlusunu açın. Gerekirse, adıyla aramak için Filtre metni girdisi alanını kullanın.
- Hizmet sorumlusu ayrıntıları sayfasında Uygulama Kimliğini kaydedin. Databricks SQL erişimi ve Çalışma alanı erişimi onay kutularının seçili olduğunu doğrulayın.
2. Adım: OAuth gizli dizisi oluşturma
Hizmet sorumlusu için bir gizli dizi oluşturun ve dış uygulamanız için ihtiyacınız olacak aşağıdaki yapılandırma değerlerini toplayın:
- Hizmet sorumlusu (istemci) kimliği
- İstemci gizliliği
Hizmet sorumlusu, dış uygulamanızdan erişim belirteci isteğinde bulunurken kimliğini doğrulamak için bir OAuth gizli dizisi kullanır.
Gizli dizi oluşturmak için:
- Hizmet sorumlusu ayrıntıları sayfasında Gizli Diziler'e tıklayın.
- Gizli dizi oluştur'a tıklayın.
- Yeni gizli dizi için gün cinsinden bir yaşam süresi değeri girin (örneğin, 1 ile 730 gün arasında).
- Gizli diziyi hemen kopyalayın. Bu ekrandan ayrıldıktan sonra bu gizli diziyi yeniden görüntüleyemezsiniz.
3. Adım: Hizmet sorumlunuza izin atama
Oluşturduğunuz hizmet sorumlusu, uygulamanız üzerinden pano erişimi sağlayan kimlik görevi görür. Pano, paylaşılan veri izinleriyle yayımlanmadıysa izinleri yalnızca geçerlidir. Paylaşılan veri izinleri kullanılıyorsa, yayımcının kimlik bilgileri verilere erişiyor. Diğer ayrıntılar ve öneriler için bkz . Kimlik doğrulama yaklaşımlarını ekleme.
- Pano listesi sayfasını açmak için çalışma alanı kenar çubuğunda Panolar'a tıklayın.
- Eklemek istediğiniz panonun adına tıklayın. Yayımlanan pano açılır.
- Paylaş’a tıklayın.
- Paylaşım iletişim kutusundaki metin girişi alanını kullanarak hizmet sorumlunuzu bulun ve üzerine tıklayın. İzin düzeyini CAN RUN olarak ayarlayın. Ardından Ekle'ye tıklayın.
-
Pano kimliğini kaydedin. Pano kimliğini panonun URL'sinde bulabilirsiniz (ör.
https://<your-workspace-url>/dashboards/<dashboard-id>). Bkz. Databricks çalışma alanı ayrıntıları.
Uyarı
Tek tek veri izinlerine sahip bir pano yayımlarsanız, hizmet sorumlunuza panoda kullanılan verilere erişim izni vermelisiniz. İşlem erişimi her zaman yayımcının kimlik bilgilerini kullanır, bu nedenle hizmet sorumlusuna işlem izinleri vermeniz gerekmez.
Verileri okumak ve görüntülemek için hizmet sorumlusunun panoda başvuruda bulunan tablo ve görünümlerde en az SELECT ayrıcalıklara sahip olması gerekir. Bkz . Ayrıcalıkları kimler yönetebilir?.
4. Adım: Kimlik doğrulaması yapmak ve belirteç oluşturmak için örnek uygulamayı kullanma
Panonuzu dışarıdan ekleme alıştırması yapmak için örnek bir uygulama kullanın. Uygulamalar, kapsamlı belirteçler oluşturmak için gerekli belirteç değişimini başlatan yönergeler ve kod içerir. Aşağıdaki kod bloklarının bağımlılıkları yoktur. Aşağıdaki uygulamalardan birini kopyalayın ve kaydedin.
Piton
Bunu kopyalayın ve adlı example.pybir dosyaya kaydedin.
#!/usr/bin/env python3
import os
import sys
import json
import base64
import urllib.request
import urllib.parse
from http.server import HTTPServer, BaseHTTPRequestHandler
# -----------------------------------------------------------------------------
# Config
# -----------------------------------------------------------------------------
CONFIG = {
"instance_url": os.environ.get("INSTANCE_URL"),
"dashboard_id": os.environ.get("DASHBOARD_ID"),
"service_principal_id": os.environ.get("SERVICE_PRINCIPAL_ID"),
"service_principal_secret": os.environ.get("SERVICE_PRINCIPAL_SECRET"),
"external_viewer_id": os.environ.get("EXTERNAL_VIEWER_ID"),
"external_value": os.environ.get("EXTERNAL_VALUE"),
"workspace_id": os.environ.get("WORKSPACE_ID"),
"port": int(os.environ.get("PORT", 3000)),
}
basic_auth = base64.b64encode(
f"{CONFIG['service_principal_id']}:{CONFIG['service_principal_secret']}".encode()
).decode()
# -----------------------------------------------------------------------------
# HTTP Request Helper
# -----------------------------------------------------------------------------
def http_request(url, method="GET", headers=None, body=None):
headers = headers or {}
if body is not None and not isinstance(body, (bytes, str)):
raise ValueError("Body must be bytes or str")
req = urllib.request.Request(url, method=method, headers=headers)
if body is not None:
if isinstance(body, str):
body = body.encode()
req.data = body
try:
with urllib.request.urlopen(req) as resp:
data = resp.read().decode()
try:
return {"data": json.loads(data)}
except json.JSONDecodeError:
return {"data": data}
except urllib.error.HTTPError as e:
raise RuntimeError(f"HTTP {e.code}: {e.read().decode()}") from None
# -----------------------------------------------------------------------------
# Token logic
# -----------------------------------------------------------------------------
def get_scoped_token():
# 1. Get all-api token
oidc_res = http_request(
f"{CONFIG['instance_url']}/oidc/v1/token",
method="POST",
headers={
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": f"Basic {basic_auth}",
},
body=urllib.parse.urlencode({
"grant_type": "client_credentials",
"scope": "all-apis"
})
)
oidc_token = oidc_res["data"]["access_token"]
# 2. Get token info
token_info_url = (
f"{CONFIG['instance_url']}/api/2.0/lakeview/dashboards/"
f"{CONFIG['dashboard_id']}/published/tokeninfo"
f"?external_viewer_id={urllib.parse.quote(CONFIG['external_viewer_id'])}"
f"&external_value={urllib.parse.quote(CONFIG['external_value'])}"
)
token_info = http_request(
token_info_url,
headers={"Authorization": f"Bearer {oidc_token}"}
)["data"]
# 3. Generate scoped token
params = token_info.copy()
authorization_details = params.pop("authorization_details", None)
params.update({
"grant_type": "client_credentials",
"authorization_details": json.dumps(authorization_details)
})
scoped_res = http_request(
f"{CONFIG['instance_url']}/oidc/v1/token",
method="POST",
headers={
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": f"Basic {basic_auth}",
},
body=urllib.parse.urlencode(params)
)
return scoped_res["data"]["access_token"]
# -----------------------------------------------------------------------------
# HTML generator
# -----------------------------------------------------------------------------
def generate_html(token):
return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard Demo</title>
<style>
body {{ font-family: system-ui; margin: 0; padding: 20px; background: #f5f5f5; }}
.container {{ max-width: 1200px; margin: 0 auto; height:calc(100vh - 40px) }}
</style>
</head>
<body>
<div id="dashboard-content" class="container"></div>
<script type="module">
import {{ DatabricksDashboard }} from "https://cdn.jsdelivr.net/npm/@databricks/aibi-client@0.0.0-alpha.7/+esm";
const dashboard = new DatabricksDashboard({{
instanceUrl: "{CONFIG['instance_url']}",
workspaceId: "{CONFIG['workspace_id']}",
dashboardId: "{CONFIG['dashboard_id']}",
token: "{token}",
container: document.getElementById("dashboard-content")
}});
dashboard.initialize();
</script>
</body>
</html>"""
# -----------------------------------------------------------------------------
# HTTP server
# -----------------------------------------------------------------------------
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path != "/":
self.send_response(404)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(b"Not Found")
return
try:
token = get_scoped_token()
html = generate_html(token)
status = 200
except Exception as e:
html = f"<h1>Error</h1><p>{e}</p>"
status = 500
self.send_response(status)
self.send_header("Content-Type", "text/html")
self.end_headers()
self.wfile.write(html.encode())
def start_server():
missing = [k for k, v in CONFIG.items() if not v]
if missing:
print(f"Missing: {', '.join(missing)}", file=sys.stderr)
sys.exit(1)
server = HTTPServer(("localhost", CONFIG["port"]), RequestHandler)
print(f":rocket: Server running on http://localhost:{CONFIG['port']}")
try:
server.serve_forever()
except KeyboardInterrupt:
sys.exit(0)
if __name__ == "__main__":
start_server()
JavaScript
Bunu kopyalayın ve adlı example.jsbir dosyaya kaydedin.
#!/usr/bin/env node
const http = require('http');
const https = require('https');
const { URL, URLSearchParams } = require('url');
// This constant is just a mapping of environment variables to their respective
// values.
const CONFIG = {
instanceUrl: process.env.INSTANCE_URL,
dashboardId: process.env.DASHBOARD_ID,
servicePrincipalId: process.env.SERVICE_PRINCIPAL_ID,
servicePrincipalSecret: process.env.SERVICE_PRINCIPAL_SECRET,
externalViewerId: process.env.EXTERNAL_VIEWER_ID,
externalValue: process.env.EXTERNAL_VALUE,
workspaceId: process.env.WORKSPACE_ID,
port: process.env.PORT || 3000,
};
const basicAuth = Buffer.from(`${CONFIG.servicePrincipalId}:${CONFIG.servicePrincipalSecret}`).toString('base64');
// ------------------------------------------------------------------------------------------------
// Main
// ------------------------------------------------------------------------------------------------
function startServer() {
const missing = Object.keys(CONFIG).filter((key) => !CONFIG[key]);
if (missing.length > 0) throw new Error(`Missing: ${missing.join(', ')}`);
const server = http.createServer(async (req, res) => {
// This is a demo server, we only support GET requests to the root URL.
if (req.method !== 'GET' || req.url !== '/') {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
return;
}
let html = '';
let status = 200;
try {
const token = await getScopedToken();
html = generateHTML(token);
} catch (error) {
html = `<h1>Error</h1><p>${error.message}</p>`;
status = 500;
} finally {
res.writeHead(status, { 'Content-Type': 'text/html' });
res.end(html);
}
});
server.listen(CONFIG.port, () => {
console.log(`🚀 Server running on http://localhost:${CONFIG.port}`);
});
process.on('SIGINT', () => process.exit(0));
process.on('SIGTERM', () => process.exit(0));
}
async function getScopedToken() {
// 1. Get all-api token. This will allow you to access the /tokeninfo
// endpoint, which contains the information required to generate a scoped token
const {
data: { access_token: oidcToken },
} = await httpRequest(`${CONFIG.instanceUrl}/oidc/v1/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${basicAuth}`,
},
body: new URLSearchParams({
grant_type: 'client_credentials',
scope: 'all-apis',
}),
});
// 2. Get token info. This information is **required** for generating a token that is correctly downscoped.
// A correctly downscoped token will only have access to a handful of APIs, and within those APIs, only
// a the specific resources required to render the dashboard.
//
// This is essential to prevent leaking a privileged token.
//
// At the time of writing, OAuth tokens in Databricks are valid for 1 hour.
const tokenInfoUrl = new URL(
`${CONFIG.instanceUrl}/api/2.0/lakeview/dashboards/${CONFIG.dashboardId}/published/tokeninfo`,
);
tokenInfoUrl.searchParams.set('external_viewer_id', CONFIG.externalViewerId);
tokenInfoUrl.searchParams.set('external_value', CONFIG.externalValue);
const { data: tokenInfo } = await httpRequest(tokenInfoUrl.toString(), {
headers: { Authorization: `Bearer ${oidcToken}` },
});
// 3. Generate scoped token. This call is very similar to what was issued before, but now we are providing the scoping to make the generated token
// safe to pass to a browser.
const { authorization_details, ...params } = tokenInfo;
const {
data: { access_token },
} = await httpRequest(`${CONFIG.instanceUrl}/oidc/v1/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${basicAuth}`,
},
body: new URLSearchParams({
grant_type: 'client_credentials',
...params,
authorization_details: JSON.stringify(authorization_details),
}),
});
return access_token;
}
startServer();
// ------------------------------------------------------------------------------------------------
// Helper functions
// ------------------------------------------------------------------------------------------------
/**
* Helper function to create HTTP requests.
* @param {string} url - The URL to make the request to.
* @param {Object} options - The options for the request.
* @param {string} options.method - The HTTP method to use.
* @param {Object} options.headers - The headers to include in the request.
* @param {Object} options.body - The body to include in the request.
* @returns {Promise<Object>} A promise that resolves to the response data.
*/
function httpRequest(url, { method = 'GET', headers = {}, body } = {}) {
return new Promise((resolve, reject) => {
const isHttps = url.startsWith('https://');
const lib = isHttps ? https : http;
const options = new URL(url);
options.method = method;
options.headers = headers;
const req = lib.request(options, (res) => {
let data = '';
res.on('data', (chunk) => (data += chunk));
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
try {
resolve({ data: JSON.parse(data) });
} catch {
resolve({ data });
}
} else {
reject(new Error(`HTTP ${res.statusCode}: ${data}`));
}
});
});
req.on('error', reject);
if (body) {
if (typeof body === 'string' || Buffer.isBuffer(body)) {
req.write(body);
} else if (body instanceof URLSearchParams) {
req.write(body.toString());
} else {
req.write(JSON.stringify(body));
}
}
req.end();
});
}
function generateHTML(token) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard Demo</title>
<style>
body { font-family: system-ui; margin: 0; padding: 20px; background: #f5f5f5; }
.container { max-width: 1200px; margin: 0 auto; height:calc(100vh - 40px) }
</style>
</head>
<body>
<div id="dashboard-content" class="container"></div>
<script type="module">
/**
* We recommend bundling the dependency instead of using a CDN. However, for demonstration purposes,
* we are just using a CDN.
*
* We do not recommend one CDN over another and encourage decoupling the dependency from third-party code.
*/
import { DatabricksDashboard } from "https://cdn.jsdelivr.net/npm/@databricks/aibi-client@0.0.0-alpha.7/+esm";
const dashboard = new DatabricksDashboard({
instanceUrl: "${CONFIG.instanceUrl}",
workspaceId: "${CONFIG.workspaceId}",
dashboardId: "${CONFIG.dashboardId}",
token: "${token}",
container: document.getElementById("dashboard-content")
});
dashboard.initialize();
</script>
</body>
</html>`;
}
5. Adım: Örnek uygulamayı çalıştırma
Aşağıdaki değerleri değiştirin ve ardından kod bloğunu terminalden çalıştırın. Değerleriniz açılı ayraçlarla () < >:
- Aşağıdaki değerleri bulmak ve değiştirmek için çalışma alanı URL'sini kullanın:
<your-instance><workspace_id><dashboard_id>
- Aşağıdaki değerleri hizmet sorumlusunu oluştururken oluşturduğunuz değerlerle değiştirin (2. adım):
<service_principal_id>-
<service_principal_secret>(istemci gizli dizisi)
- Aşağıdaki değerleri dış uygulamanın kullanıcılarıyla ilişkilendirilmiş tanımlayıcılarla değiştirin:
<some-external-viewer><some-external-value>
- değerini önceki adımda oluşturduğunuz veya
</path/to/example>dosyasının yoluyla.pydeğiştirin.js. Dosya uzantısını ekleyin.
Uyarı
Değere kişisel bilgileri (PII) eklemeyin EXTERNAL_VIEWER_ID .
INSTANCE_URL='https://<your-instance>.databricks.com' \
WORKSPACE_ID='<workspace_id>' \
DASHBOARD_ID='<dashboard_id>' \
SERVICE_PRINCIPAL_ID='<service-principal-id>' \
SERVICE_PRINCIPAL_SECRET='<service-principal_secret>' \
EXTERNAL_VIEWER_ID='<some-external-viewer>' \
EXTERNAL_VALUE='<some-external-value>' \
~</path/to/example>
# Terminal will output: :rocket: Server running on http://localhost:3000