web/vtctld: Port schema manager to new UI.

This commit is contained in:
Anthony Yeh 2015-07-22 17:29:43 -07:00
Родитель 34e4d370bb
Коммит 800c699a67
8 изменённых файлов: 105 добавлений и 8 удалений

Просмотреть файл

@ -4,17 +4,24 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"reflect"
"strings"
"github.com/youtube/vitess/go/vt/schemamanager"
"github.com/youtube/vitess/go/vt/tabletmanager/tmclient"
"github.com/youtube/vitess/go/vt/topo"
"golang.org/x/net/context"
)
// This file implements a REST-style API for the vtctld web interface.
const apiPrefix = "/api/"
const (
apiPrefix = "/api/"
jsonContentType = "application/json; charset=utf-8"
)
func handleCollection(collection string, getFunc func(*http.Request) (interface{}, error)) {
http.HandleFunc(apiPrefix+collection+"/", func(w http.ResponseWriter, r *http.Request) {
@ -31,6 +38,7 @@ func handleCollection(collection string, getFunc func(*http.Request) (interface{
// JSON marshals a nil slice as "null", but we prefer "[]".
if val := reflect.ValueOf(obj); val.Kind() == reflect.Slice && val.IsNil() {
w.Header().Set("Content-Type", jsonContentType)
w.Write([]byte("[]"))
return
}
@ -41,6 +49,7 @@ func handleCollection(collection string, getFunc func(*http.Request) (interface{
httpErrorf(w, r, "json error: %v", err)
return
}
w.Header().Set("Content-Type", jsonContentType)
w.Write(data)
})
}
@ -60,6 +69,14 @@ func getItemPath(url string) string {
return parts[1]
}
func unmarshalRequest(r *http.Request, v interface{}) error {
data, err := ioutil.ReadAll(r.Body)
if err != nil {
return err
}
return json.Unmarshal(data, v)
}
func initAPI(ctx context.Context, ts topo.Server, actions *ActionRepository) {
tabletHealthCache := newTabletHealthCache(ts)
@ -206,4 +223,20 @@ func initAPI(ctx context.Context, ts topo.Server, actions *ActionRepository) {
ep, _, err := ts.GetEndPoints(ctx, parts[0], parts[1], parts[2], topo.TabletType(parts[3]))
return ep, err
})
// Schema Change
http.HandleFunc(apiPrefix+"schema/apply", func(w http.ResponseWriter, r *http.Request) {
req := struct{ Keyspace, SQL string }{}
if err := unmarshalRequest(r, &req); err != nil {
httpErrorf(w, r, "can't unmarshal request: %v", err)
return
}
executor := schemamanager.NewTabletExecutor(
tmclient.NewTabletManagerClient(),
ts)
schemamanager.Run(ctx,
schemamanager.NewUIController(req.SQL, req.Keyspace, w), executor)
})
}

Просмотреть файл

@ -19,8 +19,9 @@
</div>
<md-content ng-if="result.$resolved" class="md-padding">
<h2 ng-bind="result.Error === undefined || result.Error ? 'Action Failed' : 'Action Succeeded'"></h2>
<p ng-bind="result.Output"></p>
<h2 ng-if="result.Error">Action Failed</h2>
<h2 ng-if="!result.Error && !result.Output">Action Succeeded</h2>
<pre ng-bind="result.Output"></pre>
</md-content>
</md-dialog-content>

Просмотреть файл

@ -51,7 +51,7 @@ app.factory('actions', function($mdDialog, keyspaces, shards, tablets) {
keyspace: keyspace,
shard: shard,
action: action.name
}, '');
}, '');
showResult(ev, action, result);
});
};
@ -66,6 +66,12 @@ app.factory('actions', function($mdDialog, keyspaces, shards, tablets) {
});
};
svc.applyFunc = function(ev, action, func) {
confirm(ev, action, function() {
showResult(ev, action, func());
});
};
svc.label = function(action) {
return action.confirm ? action.title + '...' : action.title;
};

Просмотреть файл

@ -76,3 +76,7 @@ md-toolbar h1 {
font-size: 1.5em;
font-weight: 900;
}
textarea.code {
font-family: monospace;
}

Просмотреть файл

@ -68,7 +68,10 @@ app.controller('AppCtrl', function($scope, $mdSidenav, $route, $location,
$scope.routes = routes;
$scope.refreshRoute = function() {
$route.current.locals.$scope.refreshData();
if ($route.current && $route.current.locals.$scope.refreshData)
$route.current.locals.$scope.refreshData();
else
$route.reload();
};
$scope.toggleNav = function() { $mdSidenav('left').toggle(); }
@ -85,6 +88,3 @@ app.controller('AppCtrl', function($scope, $mdSidenav, $route, $location,
$location.path(path);
};
});
app.controller('SchemaCtrl', function() {
});

Просмотреть файл

@ -69,6 +69,7 @@
<script src="./shard.js"></script>
<script src="./topo.js"></script>
<script src="./actions.js"></script>
<script src="./schema.js"></script>
</body>
</html>

Просмотреть файл

@ -1 +1,20 @@
<md-content class="md-padding">
<md-tabs md-border-bottom md-center-tabs="false">
<md-tab label="Apply Schema">
<md-select placeholder="Select Keyspace" ng-model="schemaChange.Keyspace">
<md-option ng-repeat="keyspace in keyspaces" value="{{keyspace}}">{{keyspace}}</md-option>
</md-select>
<md-input-container flex>
<label>Schema Change SQL</label>
<textarea ng-model="schemaChange.SQL" class="code"></textarea>
</md-input-container>
<md-button class="md-primary" ng-click="submitSchema($event)">Submit</md-button>
</md-tab>
</md-tabs>
</md-content>

33
web/vtctld/schema.js Normal file
Просмотреть файл

@ -0,0 +1,33 @@
app.controller('SchemaCtrl', function($scope, $http, $mdDialog,
actions, keyspaces) {
$scope.schemaChange = {Keyspace: '', SQL: ''};
$scope.refreshData = function() {
$scope.keyspaces = keyspaces.query();
};
$scope.refreshData();
$scope.submitSchema = function(ev) {
var action = {
title: 'Apply Schema',
confirm: 'This will execute the provided SQL on all shards in the keyspace.'
};
actions.applyFunc(ev, action, function() {
var result = {$resolved: false};
$http.post('/api/schema/apply', $scope.schemaChange)
.success(function(data) {
result.$resolved = true;
result.Output = data;
result.Error = false;
})
.error(function(data) {
result.$resolved = true;
result.Output = data;
result.Error = true;
});
return result;
});
};
});