Skip to content

Commit c2b8d08

Browse files
authored
Merge branch 'master' into dremio-date-interval-fix
2 parents 6b65010 + 97af50e commit c2b8d08

File tree

22 files changed

+404
-7
lines changed

22 files changed

+404
-7
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
module.exports = {
22
"aws": "AWS",
3+
"azure": "Azure",
34
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Deploying Cube Cloud BYOC on Azure
2+
3+
With Bring Your Own Cloud (BYOC) on Azure, all the components interacting with private data are deployed on
4+
the customer infrastructure on Azure and managed by the Cube Cloud Control Plane via the Cube Cloud Operator.
5+
This document provides step-by-step instructions for deploying Cube Cloud BYOC on Azure.
6+
7+
## Overall Design
8+
Cube Cloud will gain access to your Azure account via the Cube Cloud Provisioner Enterprise App.
9+
10+
It will leverage a dedicated subscription where it will create a new Resource
11+
Group and bootstrap all the necessary infrastructure. At the center of the BYOC
12+
infrastructure are two AKS clusters that provide compute resources for the Cube
13+
Store and all Cube deployments you configure in the Cube Cloud UI. These AKS
14+
clusters will have a Cube Cloud operator installed in them that is connected to
15+
the Cube Cloud Control Plane. The Cube Cloud Operator receives instructions
16+
from the Control Plane and dynamically creates or destroys all the necessary
17+
Kubernetes resources required to support your Cube deployments.
18+
19+
<div style={{ textAlign: "center" }}>
20+
<img
21+
alt="High-level diagram of Cube Cloud resources deployed on Azure"
22+
src="https://ucarecdn.com/6d0f12db-086c-4274-b165-da68ccc381a9/"
23+
style={{ border: "none" }}
24+
width="100%"
25+
/>
26+
</div>
27+
28+
## Prerequisites
29+
30+
The bulk of provisioning work will be done remotely by Cube Cloud automation.
31+
However, to get started, you'll need to provide Cube with the necessary access
32+
along with some additional information that includes:
33+
34+
- **Azure Tenant ID** - the Entra ID of your Azure account
35+
- **Azure Subscription ID** - The target subscription where Cube Cloud will be granted admin permissions to provision the BYOC infrastructure
36+
- **Region** - The target Azure region where Cube Cloud BYOC will be installed
37+
38+
## Provisioning access
39+
40+
### Add Cube tenant to your organization
41+
42+
First you should add the Cube Cloud tenant to your organization. To do this,
43+
open the [Azure Portal][azure-console] and go to&nbsp;<Btn>Azure Active
44+
Directory</Btn> →&nbsp;<Btn>External Identities</Btn> →&nbsp;<Btn>Cross-tenant
45+
access settings</Btn> →&nbsp;<Btn>Organizational Settings</Btn>
46+
&nbsp;<Btn>Add Organization</Btn>.
47+
48+
For Tenant ID, enter `197e5263-87f4-4ce1-96c4-351b0c0c714a`.
49+
50+
Make sure that&nbsp;<Btn>B2B Collaboration</Btn> →&nbsp;<Btn>Inbound Access</Btn>
51+
&nbsp;<Btn>Applications</Btn> is set to&nbsp;<Btn>Allows access</Btn>.
52+
53+
### Register Cube Cloud service principal at your organization
54+
55+
To register the Cube Cloud service principal for your organization, follow these
56+
steps:
57+
58+
1. Log in with an account that has permissions to register Enterprise
59+
applications.
60+
2. Open a browser tab and go to the following URL, replacing `<TENANT_ID>` with
61+
your tenant ID:
62+
`https://login.microsoftonline.com/<TENANT_ID>/oauth2/authorize?client_id=0c5d0d4b-6cee-402e-9a08-e5b79f199481&response_type=code&redirect_uri=https%3A%2F%2Fwww.microsoft.com%2F`
63+
3. The Cube Cloud service principal has specific credentials. Check that the
64+
following details match exactly what you see on the dialog box that pops up:
65+
66+
- Client ID: `d1c59948-4d4a-43dc-8d04-c0df8795ae19`
67+
- Name: `cube-cloud-byoc-provisioner`
68+
69+
Once you have confirmed that all the information is correct,
70+
select&nbsp;<Btn>Consent on behalf of your organization</Btn> and
71+
click&nbsp;<Btn>Accept</Btn>.
72+
73+
### Grant admin permissions on your BYOC Azure Subscription to the cube-cloud-byoc-provisioner
74+
75+
On the [Azure Portal][azure-console], go to&nbsp;<Btn>Subscriptions</Btn>
76+
_Your BYOC Subscription_&nbsp;<Btn>IAM</Btn>→&nbsp;<Btn>Role Assignment</Btn>
77+
and assing `Contributor` and `Role Based Access Control Administrator` to the `cube-cloud-byoc-provisioner`
78+
Service Principal.
79+
80+
<Screenshot src="https://ucarecdn.com/e1e917cd-6992-4864-b20e-0fbf7688a7e5/"/>
81+
82+
## Deployment
83+
84+
The actual deployment will be done by Cube Cloud automation. All that's left to
85+
do is notify your Cube contact point that access has been granted, and pass
86+
along your Azure Tenant/Subscription/Region information.
87+
88+
[azure-console]: https://portal.azure.com

docs/pages/product/deployment/cloud/continuous-deployment.mdx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ First, ensure your deployment is configured to deploy with Git. Then connect
3434
your GitHub repository to your deployment by clicking the <Btn>Connect to
3535
GitHub</Btn> button, and selecting your repository.
3636

37+
<WarningBox>
38+
39+
If your organization uses SAML SSO for GitHub authentication, make sure to start an active SAML
40+
session prior to connecting to your GitHub account from Cube.
41+
42+
<WarningBox>
43+
3744
<div style={{ textAlign: "center" }}>
3845
<img
3946
src="https://ucarecdn.com/3dab6d90-6bd9-44a5-ae4d-d5579a08dd89/"

packages/cubejs-api-gateway/openspec.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,20 @@ components:
170170
type: array
171171
items:
172172
type: "string"
173+
V1CubeMetaHierarchy:
174+
type: "object"
175+
required:
176+
- name
177+
- levels
178+
properties:
179+
name:
180+
type: "string"
181+
title:
182+
type: "string"
183+
levels:
184+
type: "array"
185+
items:
186+
type: "string"
173187
V1CubeMeta:
174188
type: "object"
175189
required:
@@ -209,6 +223,10 @@ components:
209223
type: "array"
210224
items:
211225
$ref: "#/components/schemas/V1CubeMetaFolder"
226+
hierarchies:
227+
type: "array"
228+
items:
229+
$ref: "#/components/schemas/V1CubeMetaHierarchy"
212230
V1CubeMetaType:
213231
type: "string"
214232
description: Type of cube

packages/cubejs-schema-compiler/src/compiler/DataSchemaCompiler.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ export class DataSchemaCompiler {
2323
this.cubeCompilers = options.cubeCompilers || [];
2424
this.contextCompilers = options.contextCompilers || [];
2525
this.transpilers = options.transpilers || [];
26+
this.viewCompilers = options.viewCompilers || [];
2627
this.preTranspileCubeCompilers = options.preTranspileCubeCompilers || [];
28+
this.viewCompilationGate = options.viewCompilationGate;
2729
this.cubeNameCompilers = options.cubeNameCompilers || [];
2830
this.extensions = options.extensions || {};
2931
this.cubeFactory = options.cubeFactory;
@@ -93,7 +95,10 @@ export class DataSchemaCompiler {
9395
const compilePhase = (compilers) => this.compileCubeFiles(compilers, transpile(), errorsReport);
9496

9597
return compilePhase({ cubeCompilers: this.cubeNameCompilers })
96-
.then(() => compilePhase({ cubeCompilers: this.preTranspileCubeCompilers }))
98+
.then(() => compilePhase({ cubeCompilers: this.preTranspileCubeCompilers.concat([this.viewCompilationGate]) }))
99+
.then(() => (this.viewCompilationGate.shouldCompileViews() ?
100+
compilePhase({ cubeCompilers: this.viewCompilers })
101+
: Promise.resolve()))
97102
.then(() => compilePhase({
98103
cubeCompilers: this.cubeCompilers,
99104
contextCompilers: this.contextCompilers,

packages/cubejs-schema-compiler/src/compiler/PrepareCompiler.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { JoinGraph } from './JoinGraph';
2020
import { CubeToMetaTransformer } from './CubeToMetaTransformer';
2121
import { CompilerCache } from './CompilerCache';
2222
import { YamlCompiler } from './YamlCompiler';
23+
import { ViewCompilationGate } from './ViewCompilationGate';
2324

2425
export type PrepareCompilerOptions = {
2526
nativeInstance?: NativeInstance,
@@ -37,19 +38,21 @@ export const prepareCompiler = (repo: SchemaFileRepository, options: PrepareComp
3738
const nativeInstance = options.nativeInstance || new NativeInstance();
3839
const cubeDictionary = new CubeDictionary();
3940
const cubeSymbols = new CubeSymbols();
41+
const viewCompiler = new CubeSymbols(true);
42+
const viewCompilationGate = new ViewCompilationGate();
4043
const cubeValidator = new CubeValidator(cubeSymbols);
4144
const cubeEvaluator = new CubeEvaluator(cubeValidator);
4245
const contextEvaluator = new ContextEvaluator(cubeEvaluator);
4346
const joinGraph = new JoinGraph(cubeValidator, cubeEvaluator);
4447
const metaTransformer = new CubeToMetaTransformer(cubeValidator, cubeEvaluator, contextEvaluator, joinGraph);
4548
const { maxQueryCacheSize, maxQueryCacheAge } = options;
4649
const compilerCache = new CompilerCache({ maxQueryCacheSize, maxQueryCacheAge });
47-
const yamlCompiler = new YamlCompiler(cubeSymbols, cubeDictionary, nativeInstance);
50+
const yamlCompiler = new YamlCompiler(cubeSymbols, cubeDictionary, nativeInstance, viewCompiler);
4851

4952
const transpilers: TranspilerInterface[] = [
5053
new ValidationTranspiler(),
5154
new ImportExportTranspiler(),
52-
new CubePropContextTranspiler(cubeSymbols, cubeDictionary),
55+
new CubePropContextTranspiler(cubeSymbols, cubeDictionary, viewCompiler),
5356
];
5457

5558
if (!options.allowJsDuplicatePropsInSchema) {
@@ -60,6 +63,8 @@ export const prepareCompiler = (repo: SchemaFileRepository, options: PrepareComp
6063
cubeNameCompilers: [cubeDictionary],
6164
preTranspileCubeCompilers: [cubeSymbols, cubeValidator],
6265
transpilers,
66+
viewCompilationGate,
67+
viewCompilers: [viewCompiler],
6368
cubeCompilers: [cubeEvaluator, joinGraph, metaTransformer],
6469
contextCompilers: [contextEvaluator],
6570
cubeFactory: cubeSymbols.createCube.bind(cubeSymbols),
@@ -72,7 +77,7 @@ export const prepareCompiler = (repo: SchemaFileRepository, options: PrepareComp
7277
compileContext: options.compileContext,
7378
standalone: options.standalone,
7479
nativeInstance,
75-
yamlCompiler
80+
yamlCompiler,
7681
}, options));
7782

7883
return {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
export class ViewCompilationGate {
2+
private shouldCompile: any;
3+
4+
public constructor() {
5+
this.shouldCompile = false;
6+
}
7+
8+
public compile(cubes: any[]) {
9+
// When developing Data Access Policies feature, we've came across a
10+
// limitation that Cube members can't be referenced in access policies defined on Views,
11+
// because views aren't (yet) compiled at the time of access policy evaluation.
12+
// To workaround this limitation and additional compilation pass is necessary,
13+
// however it comes with a significant performance penalty.
14+
// This gate check whether the data model contains views with access policies,
15+
// and only then allows the additional compilation pass.
16+
//
17+
// Check out the DataSchemaCompiler.ts to see how this gate is used.
18+
if (this.viewsHaveAccessPolicies(cubes)) {
19+
this.shouldCompile = true;
20+
}
21+
}
22+
23+
private viewsHaveAccessPolicies(cubes: any[]) {
24+
return cubes.some(c => c.isView && c.accessPolicy);
25+
}
26+
27+
public shouldCompileViews() {
28+
return this.shouldCompile;
29+
}
30+
}

packages/cubejs-schema-compiler/src/compiler/YamlCompiler.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export class YamlCompiler {
3333
private readonly cubeSymbols: CubeSymbols,
3434
private readonly cubeDictionary: CubeDictionary,
3535
private readonly nativeInstance: NativeInstance,
36+
private readonly viewCompiler: CubeSymbols,
3637
) {
3738
}
3839

@@ -288,7 +289,9 @@ export class YamlCompiler {
288289
},
289290
);
290291

291-
resolveSymbol = resolveSymbol || (n => this.cubeSymbols.resolveSymbol(cubeName, n) || this.cubeSymbols.isCurrentCube(n));
292+
resolveSymbol = resolveSymbol || (n => this.viewCompiler.resolveSymbol(cubeName, n) ||
293+
this.cubeSymbols.resolveSymbol(cubeName, n) ||
294+
this.cubeSymbols.isCurrentCube(n));
292295

293296
const traverseObj = {
294297
Program: (babelPath) => {

packages/cubejs-schema-compiler/src/compiler/transpilers/CubePropContextTranspiler.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export class CubePropContextTranspiler implements TranspilerInterface {
4141
public constructor(
4242
protected readonly cubeSymbols: CubeSymbols,
4343
protected readonly cubeDictionary: CubeDictionary,
44+
protected readonly viewCompiler: CubeSymbols,
4445
) {
4546
}
4647

@@ -88,7 +89,9 @@ export class CubePropContextTranspiler implements TranspilerInterface {
8889
}
8990

9091
protected sqlAndReferencesFieldVisitor(cubeName): TraverseObject {
91-
const resolveSymbol = n => this.cubeSymbols.resolveSymbol(cubeName, n) || this.cubeSymbols.isCurrentCube(n);
92+
const resolveSymbol = n => this.viewCompiler.resolveSymbol(cubeName, n) ||
93+
this.cubeSymbols.resolveSymbol(cubeName, n) ||
94+
this.cubeSymbols.isCurrentCube(n);
9295

9396
return {
9497
ObjectProperty: (path) => {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
views:
2+
- name: users_view
3+
cubes:
4+
- join_path: users
5+
includes: "*"
6+
7+
access_policy:
8+
- role: '*'
9+
row_level:
10+
filters:
11+
- member: id
12+
operator: gt
13+
values: [10]

0 commit comments

Comments
 (0)