Repository: ambari Updated Branches: refs/heads/branch-2.5 e8cef81e4 -> b5f29c9d3
AMBARI-19848. Hive View 2.0: Allow user to create database. (dipayanb) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b5f29c9d Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b5f29c9d Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b5f29c9d Branch: refs/heads/branch-2.5 Commit: b5f29c9d322ca5b3c6d3d177ff2a916e5418243b Parents: e8cef81 Author: Dipayan Bhowmick <dipayan.bhowm...@gmail.com> Authored: Mon Feb 6 11:24:12 2017 +0530 Committer: Dipayan Bhowmick <dipayan.bhowm...@gmail.com> Committed: Mon Feb 6 11:24:12 2017 +0530 ---------------------------------------------------------------------- .../CreateDatabaseQueryGenerator.java | 44 +++++++++++++ .../DeleteDatabaseQueryGenerator.java | 2 +- .../view/hive20/resources/browser/DDLProxy.java | 12 ++++ .../hive20/resources/browser/DDLService.java | 31 +++++++++ .../main/resources/ui/app/adapters/database.js | 8 +++ .../ui/app/components/create-database-form.js | 59 +++++++++++++++++ .../hive20/src/main/resources/ui/app/router.js | 1 + .../main/resources/ui/app/routes/databases.js | 4 -- .../databases/database/tables/new-database.js | 68 ++++++++++++++++++++ .../ui/app/services/table-operations.js | 11 ++++ .../components/create-database-form.hbs | 31 +++++++++ .../resources/ui/app/templates/databases.hbs | 2 +- .../databases/database/tables/new-database.hbs | 47 ++++++++++++++ 13 files changed, 314 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/CreateDatabaseQueryGenerator.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/CreateDatabaseQueryGenerator.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/CreateDatabaseQueryGenerator.java new file mode 100644 index 0000000..c72df03 --- /dev/null +++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/CreateDatabaseQueryGenerator.java @@ -0,0 +1,44 @@ +/** +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.apache.ambari.view.hive20.internal.query.generators; + +import org.apache.ambari.view.hive20.exceptions.ServiceException; +import org.apache.commons.lang3.StringUtils; +import com.google.common.base.Optional; + +public class CreateDatabaseQueryGenerator implements QueryGenerator { + public final String databaseName; + + public CreateDatabaseQueryGenerator(String databaseName) { + this.databaseName = databaseName; + } + + public String getDatabaseName() { + return databaseName; + } + + @Override + public Optional<String> getQuery() throws ServiceException { + if(StringUtils.isEmpty(this.getDatabaseName())){ + throw new ServiceException("Database name cannot be null or empty."); + } + + return Optional.of("CREATE DATABASE `" + this.getDatabaseName() + "`"); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/DeleteDatabaseQueryGenerator.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/DeleteDatabaseQueryGenerator.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/DeleteDatabaseQueryGenerator.java index 6e1e1a5..189cd5e 100644 --- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/DeleteDatabaseQueryGenerator.java +++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/DeleteDatabaseQueryGenerator.java @@ -1,4 +1,4 @@ -/* +/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java index 7210c75..f75b008 100644 --- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java +++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java @@ -44,6 +44,7 @@ import org.apache.ambari.view.hive20.internal.dto.TableResponse; import org.apache.ambari.view.hive20.internal.parsers.TableMetaParserImpl; import org.apache.ambari.view.hive20.internal.query.generators.AlterTableQueryGenerator; import org.apache.ambari.view.hive20.internal.query.generators.AnalyzeTableQueryGenerator; +import org.apache.ambari.view.hive20.internal.query.generators.CreateDatabaseQueryGenerator; import org.apache.ambari.view.hive20.internal.query.generators.CreateTableQueryGenerator; import org.apache.ambari.view.hive20.internal.query.generators.DeleteDatabaseQueryGenerator; import org.apache.ambari.view.hive20.internal.query.generators.DeleteTableQueryGenerator; @@ -310,6 +311,17 @@ public class DDLProxy { } } + public Job createDatabase(String databaseName, JobResourceManager resourceManager) throws ServiceException { + CreateDatabaseQueryGenerator queryGenerator = new CreateDatabaseQueryGenerator(databaseName); + Optional<String> deleteDatabase = queryGenerator.getQuery(); + if(deleteDatabase.isPresent()) { + String deleteQuery = deleteDatabase.get(); + return createJob("default", deleteQuery, "CREATE DATABASE " + databaseName , resourceManager); + }else{ + throw new ServiceException("Failed to generate create database query for database " + databaseName); + } + } + public Job createJob(String databaseName, String deleteQuery, String jobTitle, JobResourceManager resourceManager) throws ServiceException { LOG.info("Creating job for : {}", deleteQuery ); http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java index 5c955a2..af8e1cd 100644 --- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java +++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLService.java @@ -112,6 +112,23 @@ public class DDLService extends BaseService { } } + @POST + @Path("databases") + @Produces(MediaType.APPLICATION_JSON) + public Response createDatabase(CreateDatabaseRequestWrapper wrapper) { + String databaseId = wrapper.database.name; + Job job = null; + try { + job = proxy.createDatabase(databaseId, getResourceManager()); + JSONObject response = new JSONObject(); + response.put("job", job); + return Response.status(Response.Status.ACCEPTED).entity(response).build(); + } catch (ServiceException e) { + LOG.error("Exception occurred while delete database {}", databaseId, e); + throw new ServiceFormattedException(e); + } + } + @GET @Path("databases/{database_id}/tables") @Produces(MediaType.APPLICATION_JSON) @@ -315,4 +332,18 @@ public class DDLService extends BaseService { public static class TableMetaRequest { public TableMeta tableInfo; } + + /** + * Wrapper class for create database request + */ + public static class CreateDatabaseRequestWrapper { + public CreateDatabaseRequest database; + } + + /** + * Request class for create database + */ + public static class CreateDatabaseRequest { + public String name; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/adapters/database.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/database.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/database.js index 6333ae6..8c1fb96 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/adapters/database.js +++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/database.js @@ -22,5 +22,13 @@ export default DDLAdapter.extend({ deleteDatabase(databaseName) { let deletURL = this.urlForFindRecord(databaseName, 'database'); return this.ajax(deletURL, 'DELETE'); + }, + + createDatabase(databaseName) { + let createUrl = this.urlForFindAll('database'); + let data = { + database: { name: databaseName} + }; + return this.ajax(createUrl, 'POST', {data: data}); } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/components/create-database-form.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/create-database-form.js b/contrib/views/hive20/src/main/resources/ui/app/components/create-database-form.js new file mode 100644 index 0000000..5a7dd53 --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/components/create-database-form.js @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; + +export default Ember.Component.extend({ + classNames: ['form-horizontal'], + + errorCleaner: Ember.observer('newDatabaseName', function() { + if(this.get('error')) { + this.clearError(); + } + }), + + validate() { + if(Ember.isEmpty(this.get('newDatabaseName'))) { + this.setError("Database name cannot be empty"); + return false; + } + return true; + }, + + setError(message) { + this.set('error', true); + this.set('errorMessage', message); + }, + + clearError() { + this.set('error'); + this.set('errorMessage'); + }, + + actions: { + rename() { + if(this.validate()) { + this.sendAction('create', this.get('newDatabaseName')); + } + }, + + cancel() { + this.sendAction('cancel'); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/router.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/router.js b/contrib/views/hive20/src/main/resources/ui/app/router.js index bc9bfa5..150a3fd 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/router.js +++ b/contrib/views/hive20/src/main/resources/ui/app/router.js @@ -36,6 +36,7 @@ Router.map(function() { this.route('newtable'); this.route('database', {path: '/:databaseId'}, function() { this.route('tables', {path: '/tables'}, function() { + this.route('new-database'); this.route('new'); this.route('table', {path: '/:name'}, function() { this.route('columns'); http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/routes/databases.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases.js index fd19905..123a93f 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/routes/databases.js +++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases.js @@ -76,10 +76,6 @@ export default Ember.Route.extend({ this.get('controller').set('confirmDropDatabase', true); }, - createTable() { - console.log("Table created"); - }, - notEmptyDialogClosed() { this.get('controller').set('databaseNotEmpty', false); this.get('controller').set('databaseToDelete', undefined); http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new-database.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new-database.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new-database.js new file mode 100644 index 0000000..b421bdc --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/new-database.js @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ember from 'ember'; + +export default Ember.Route.extend({ + + tableOperations: Ember.inject.service(), + + actions: { + cancel() { + this.transitionTo('databases'); + }, + + create(newDatabaseName) { + this._createDatabase(newDatabaseName); + } + }, + + _createDatabase(newDatabaseName) { + this._modalStatus(true, 'Submitting request to create database'); + this.get('tableOperations').createDatabase(newDatabaseName).then((job) => { + this._modalStatus(true, 'Waiting for the database to be created'); + return this.get('tableOperations').waitForJobToComplete(job.get('id'), 5 * 1000); + }).then((status) => { + this._modalStatus(true, 'Successfully created database'); + this._transitionToDatabases(newDatabaseName); + }).catch((err) => { + this._modalStatus(true, 'Failed to create database'); + this._alertMessage('Failed to create database', err); + this._transitionToDatabases(); + }); + }, + + _modalStatus(status, message) { + this.controller.set('showModal', status); + if(status) { + this.controller.set('modalMessage', message); + } + }, + + _transitionToDatabases(databaseName) { + Ember.run.later(() => { + this._modalStatus(false); + this.transitionTo('databases'); + }, 2000); + }, + + _alertMessage(message, err) { + console.log(message, err); + // TODO: user alert message here + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js index 264e617..2a0aeed 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js +++ b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js @@ -67,6 +67,17 @@ export default Ember.Service.extend({ }) }, + createDatabase(database) { + return new Promise((resolve, reject) => { + this.get('store').adapterFor('database').createDatabase(database).then((data) => { + this.get('store').pushPayload(data); + resolve(this.get('store').peekRecord('job', data.job.id)); + }, (err) => { + reject(err); + }); + }) + }, + waitForJobToComplete(jobId, after) { return new Ember.RSVP.Promise((resolve, reject) => { Ember.run.later(() => { http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/templates/components/create-database-form.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/create-database-form.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/create-database-form.hbs new file mode 100644 index 0000000..00e0606 --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/create-database-form.hbs @@ -0,0 +1,31 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} + +<div class="form-group"> + <label class="col-sm-4 control-label">New Database Name</label> + <div class="col-sm-8 {{if error 'has-error'}}"> + {{input value=newDatabaseName class="form-control" placeholder="Database Name"}} + <span class="help-block">{{errorMessage}}</span> + </div> +</div> +<div class="form-group"> + <div class="col-sm-offset-4 col-sm-8"> + <button type="submit" class="btn btn-warning" {{action "rename"}}>{{fa-icon "pencil-square-o"}} Create</button> + <button type="submit" class="btn btn-primary" {{action "cancel"}}>{{fa-icon "times"}} Cancel</button> + </div> +</div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/templates/databases.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases.hbs index 9a4a892..bb4d680 100644 --- a/contrib/views/hive20/src/main/resources/ui/app/templates/databases.hbs +++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases.hbs @@ -23,8 +23,8 @@ {{fa-icon "navicon"}} </button> <ul class="dropdown-menu dropdown-menu-right"> + <li>{{#link-to "databases.database.tables.new-database" class="text-uppercase"}}{{fa-icon "plus"}} create database{{/link-to}}</li> <li><a href="#" {{action "dropDatabase"}} class="text-uppercase">{{fa-icon "trash"}} drop database</a></li> - <li><a href="#" {{action "createTable"}} class="text-uppercase">{{fa-icon "plus"}} create table</a></li> </ul> </div> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/b5f29c9d/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/new-database.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/new-database.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/new-database.hbs new file mode 100644 index 0000000..3b2b99f --- /dev/null +++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/new-database.hbs @@ -0,0 +1,47 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} + +<div class="row"> + <div class="col-md-12"> + <div class="alert alert-info"> + <p class="lead">{{fa-icon "plus" size=1}} Create Database</p> + </div> + </div> + +</div> + +<div class="row stats-section"> + <div class="col-md-6"> + {{create-database-form create="create" cancel="cancel"}} + </div> +</div> + +{{#if showModal}} + {{#modal-dialog + translucentOverlay=true + container-class="modal-dialog modal-sm"}} + <div class="modal-content"> + <div class="modal-header text-danger"> + <p class="modal-title">{{fa-icon "plus"}} Create Database</p> + </div> + <div class="modal-body text-center text-primary"> + <p>{{modalMessage}}</p> + </div> + </div><!-- /.modal-content --> + {{/modal-dialog}} +{{/if}} \ No newline at end of file