未验证 提交 7c26f88b 编写于 作者: M Marcin Maciaszczyk 提交者: GitHub

Create system banner API handler (#2607)

* Create system banner API handler

* Handle gulp params

* Apply review suggestions

* Update severity type

* Add system banner to the UI

* Increase system banner height
上级 38e6827f
...@@ -164,6 +164,16 @@ export default { ...@@ -164,6 +164,16 @@ export default {
* Directory path containing certificate files. Matches dashboard '--default-cert-dir' flag. * Directory path containing certificate files. Matches dashboard '--default-cert-dir' flag.
*/ */
defaultCertDir: gulpUtil.env.defaultCertDir !== undefined ? gulpUtil.env.defaultCertDir : '', defaultCertDir: gulpUtil.env.defaultCertDir !== undefined ? gulpUtil.env.defaultCertDir : '',
/**
* System banner message. Matches dashboard '--system-banner' flag.
*/
systemBanner: gulpUtil.env.systemBanner !== undefined ? gulpUtil.env.systemBanner : '',
/**
* System banner severity. Matches dashboard '--system-banner-severity' flag.
*/
systemBannerSeverity: gulpUtil.env.systemBannerSeverity !== undefined ?
gulpUtil.env.systemBannerSeverity :
'',
}, },
/** /**
......
...@@ -49,6 +49,14 @@ function getBackendArgs(mode) { ...@@ -49,6 +49,14 @@ function getBackendArgs(mode) {
`--auto-generate-certificates=${conf.backend.autoGenerateCerts}`, `--auto-generate-certificates=${conf.backend.autoGenerateCerts}`,
]; ];
if (conf.backend.systemBanner.length > 0) {
args.push(`--system-banner=${conf.backend.systemBanner}`);
}
if (conf.backend.systemBannerSeverity.length > 0) {
args.push(`--system-banner-severity=${conf.backend.systemBannerSeverity}`);
}
if (conf.backend.defaultCertDir.length > 0) { if (conf.backend.defaultCertDir.length > 0) {
args.push(`--default-cert-dir=${conf.backend.defaultCertDir}`); args.push(`--default-cert-dir=${conf.backend.defaultCertDir}`);
} }
......
...@@ -6482,9 +6482,9 @@ ...@@ -6482,9 +6482,9 @@
} }
}, },
"google-closure-library": { "google-closure-library": {
"version": "20170910.0.0", "version": "20171112.0.0",
"resolved": "https://registry.npmjs.org/google-closure-library/-/google-closure-library-20170910.0.0.tgz", "resolved": "https://registry.npmjs.org/google-closure-library/-/google-closure-library-20171112.0.0.tgz",
"integrity": "sha1-1hIuwkRyZy7hNHsZ6MSkPRj1e+8=", "integrity": "sha1-bGb+srdNgwmz1wUK90MGowDQGTM=",
"dev": true "dev": true
}, },
"got": { "got": {
......
...@@ -35,6 +35,7 @@ import ( ...@@ -35,6 +35,7 @@ import (
integrationapi "github.com/kubernetes/dashboard/src/app/backend/integration/api" integrationapi "github.com/kubernetes/dashboard/src/app/backend/integration/api"
"github.com/kubernetes/dashboard/src/app/backend/settings" "github.com/kubernetes/dashboard/src/app/backend/settings"
"github.com/kubernetes/dashboard/src/app/backend/sync" "github.com/kubernetes/dashboard/src/app/backend/sync"
"github.com/kubernetes/dashboard/src/app/backend/systembanner"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
...@@ -62,6 +63,8 @@ var ( ...@@ -62,6 +63,8 @@ var (
argMetricClientCheckPeriod = pflag.Int("metric-client-check-period", 30, "Time in seconds that defines how often configured metric client health check should be run. Default: 30 seconds.") argMetricClientCheckPeriod = pflag.Int("metric-client-check-period", 30, "Time in seconds that defines how often configured metric client health check should be run. Default: 30 seconds.")
argAutoGenerateCertificates = pflag.Bool("auto-generate-certificates", false, "When set to true, Dashboard will automatically generate certificates used to serve HTTPS. Default: false.") argAutoGenerateCertificates = pflag.Bool("auto-generate-certificates", false, "When set to true, Dashboard will automatically generate certificates used to serve HTTPS. Default: false.")
argEnableInsecureLogin = pflag.Bool("enable-insecure-login", false, "When enabled, Dashboard login view will also be shown when Dashboard is not served over HTTPS. Default: false.") argEnableInsecureLogin = pflag.Bool("enable-insecure-login", false, "When enabled, Dashboard login view will also be shown when Dashboard is not served over HTTPS. Default: false.")
argSystemBanner = pflag.String("system-banner", "", "When non-empty displays message to Dashboard users. Accepts simple HTML tags. Default: ''.")
argSystemBannerSeverity = pflag.String("system-banner-severity", "INFO", "Severity of system banner. Should be one of 'INFO|WARNING|ERROR'. Default: 'INFO'.")
) )
func main() { func main() {
...@@ -93,6 +96,9 @@ func main() { ...@@ -93,6 +96,9 @@ func main() {
// Init settings manager // Init settings manager
settingsManager := settings.NewSettingsManager(clientManager) settingsManager := settings.NewSettingsManager(clientManager)
// Init system banner manager
systemBannerManager := systembanner.NewSystemBannerManager(*argSystemBanner, *argSystemBannerSeverity)
// Init integrations // Init integrations
integrationManager := integration.NewIntegrationManager(clientManager) integrationManager := integration.NewIntegrationManager(clientManager)
integrationManager.Metric().ConfigureHeapster(*argHeapsterHost). integrationManager.Metric().ConfigureHeapster(*argHeapsterHost).
...@@ -103,7 +109,8 @@ func main() { ...@@ -103,7 +109,8 @@ func main() {
clientManager, clientManager,
authManager, authManager,
*argEnableInsecureLogin, *argEnableInsecureLogin,
settingsManager) settingsManager,
systemBannerManager)
if err != nil { if err != nil {
handleFatalInitError(err) handleFatalInitError(err)
} }
......
...@@ -62,6 +62,7 @@ import ( ...@@ -62,6 +62,7 @@ import (
"github.com/kubernetes/dashboard/src/app/backend/scaling" "github.com/kubernetes/dashboard/src/app/backend/scaling"
"github.com/kubernetes/dashboard/src/app/backend/search" "github.com/kubernetes/dashboard/src/app/backend/search"
"github.com/kubernetes/dashboard/src/app/backend/settings" "github.com/kubernetes/dashboard/src/app/backend/settings"
"github.com/kubernetes/dashboard/src/app/backend/systembanner"
"github.com/kubernetes/dashboard/src/app/backend/validation" "github.com/kubernetes/dashboard/src/app/backend/validation"
"golang.org/x/net/xsrftoken" "golang.org/x/net/xsrftoken"
errorsK8s "k8s.io/apimachinery/pkg/api/errors" errorsK8s "k8s.io/apimachinery/pkg/api/errors"
...@@ -92,7 +93,9 @@ type TerminalResponse struct { ...@@ -92,7 +93,9 @@ type TerminalResponse struct {
// CreateHTTPAPIHandler creates a new HTTP handler that handles all requests to the API of the backend. // CreateHTTPAPIHandler creates a new HTTP handler that handles all requests to the API of the backend.
func CreateHTTPAPIHandler(iManager integration.IntegrationManager, cManager client.ClientManager, func CreateHTTPAPIHandler(iManager integration.IntegrationManager, cManager client.ClientManager,
authManager authApi.AuthManager, enableInsecureLogin bool, sManager settings.SettingsManager) ( authManager authApi.AuthManager, enableInsecureLogin bool, sManager settings.SettingsManager,
sbManager systembanner.SystemBannerManager) (
http.Handler, error) { http.Handler, error) {
apiHandler := APIHandler{iManager: iManager, cManager: cManager} apiHandler := APIHandler{iManager: iManager, cManager: cManager}
wsContainer := restful.NewContainer() wsContainer := restful.NewContainer()
...@@ -116,6 +119,9 @@ func CreateHTTPAPIHandler(iManager integration.IntegrationManager, cManager clie ...@@ -116,6 +119,9 @@ func CreateHTTPAPIHandler(iManager integration.IntegrationManager, cManager clie
settingsHandler := settings.NewSettingsHandler(sManager) settingsHandler := settings.NewSettingsHandler(sManager)
settingsHandler.Install(apiV1Ws) settingsHandler.Install(apiV1Ws)
systemBannerHandler := systembanner.NewSystemBannerHandler(sbManager)
systemBannerHandler.Install(apiV1Ws)
apiV1Ws.Route( apiV1Ws.Route(
apiV1Ws.GET("csrftoken/{action}"). apiV1Ws.GET("csrftoken/{action}").
To(apiHandler.handleGetCsrfToken). To(apiHandler.handleGetCsrfToken).
......
...@@ -29,6 +29,7 @@ import ( ...@@ -29,6 +29,7 @@ import (
"github.com/kubernetes/dashboard/src/app/backend/client" "github.com/kubernetes/dashboard/src/app/backend/client"
"github.com/kubernetes/dashboard/src/app/backend/settings" "github.com/kubernetes/dashboard/src/app/backend/settings"
"github.com/kubernetes/dashboard/src/app/backend/sync" "github.com/kubernetes/dashboard/src/app/backend/sync"
"github.com/kubernetes/dashboard/src/app/backend/systembanner"
"k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/fake"
) )
...@@ -43,7 +44,8 @@ func TestCreateHTTPAPIHandler(t *testing.T) { ...@@ -43,7 +44,8 @@ func TestCreateHTTPAPIHandler(t *testing.T) {
cManager := client.NewClientManager("", "http://localhost:8080") cManager := client.NewClientManager("", "http://localhost:8080")
authManager := auth.NewAuthManager(cManager, getTokenManager(), authApi.AuthenticationModes{}) authManager := auth.NewAuthManager(cManager, getTokenManager(), authApi.AuthenticationModes{})
sManager := settings.NewSettingsManager(cManager) sManager := settings.NewSettingsManager(cManager)
_, err := CreateHTTPAPIHandler(nil, cManager, authManager, false, sManager) sbManager := systembanner.NewSystemBannerManager("Hello world!", "INFO")
_, err := CreateHTTPAPIHandler(nil, cManager, authManager, false, sManager, sbManager)
if err != nil { if err != nil {
t.Fatal("CreateHTTPAPIHandler() cannot create HTTP API handler") t.Fatal("CreateHTTPAPIHandler() cannot create HTTP API handler")
} }
......
// Copyright 2017 The Kubernetes Authors.
//
// Licensed 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 api
// SystemBannerManager is used for user system banner management.
type SystemBannerManager interface {
// Get system banner.
Get() *SystemBanner
}
// SystemBanner represents system banner.
type SystemBanner struct {
Message string `json:"message"`
Severity SystemBannerSeverity `json:"severity"`
}
// SystemBannerSeverity represents severity of system banner.
type SystemBannerSeverity string
const (
// SystemBannerSeverityInfo is the lowest of allowed system banner severities.
SystemBannerSeverityInfo SystemBannerSeverity = "INFO"
// SystemBannerSeverityInfo is in the middle of allowed system banner severities.
SystemBannerSeverityWarning SystemBannerSeverity = "WARNING"
// SystemBannerSeverityInfo is the highest of allowed system banner severities.
SystemBannerSeverityError SystemBannerSeverity = "ERROR"
)
// GetSeverity returns one of allowed severity values based on given parameter.
func GetSeverity(severity string) SystemBannerSeverity {
switch severity {
case string(SystemBannerSeverityWarning):
return SystemBannerSeverityWarning
case string(SystemBannerSeverityError):
return SystemBannerSeverityError
default:
return SystemBannerSeverityInfo
}
}
// Copyright 2017 The Kubernetes Authors.
//
// Licensed 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 systembanner
import (
"log"
"net/http"
restful "github.com/emicklei/go-restful"
"github.com/kubernetes/dashboard/src/app/backend/systembanner/api"
"k8s.io/apimachinery/pkg/api/errors"
)
// SystemBannerHandler manages all endpoints related to system banner management.
type SystemBannerHandler struct {
manager SystemBannerManager
}
// Install creates new endpoints for system banner management.
func (self *SystemBannerHandler) Install(ws *restful.WebService) {
ws.Route(
ws.GET("/systembanner").
To(self.handleGet).
Writes(api.SystemBanner{}))
}
func (self *SystemBannerHandler) handleGet(request *restful.Request, response *restful.Response) {
response.WriteHeaderAndEntity(http.StatusOK, self.manager.Get())
}
// handleInternalError writes the given error to the response and sets appropriate HTTP status headers.
func handleInternalError(response *restful.Response, err error) {
log.Print(err)
statusCode := http.StatusInternalServerError
statusError, ok := err.(*errors.StatusError)
if ok && statusError.Status().Code > 0 {
statusCode = int(statusError.Status().Code)
}
response.AddHeader("Content-Type", "text/plain")
response.WriteErrorString(statusCode, err.Error()+"\n")
}
// NewSystemBannerHandler creates SystemBannerHandler.
func NewSystemBannerHandler(manager SystemBannerManager) SystemBannerHandler {
return SystemBannerHandler{manager: manager}
}
// Copyright 2017 The Kubernetes Authors.
//
// Licensed 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 systembanner
import (
"github.com/kubernetes/dashboard/src/app/backend/systembanner/api"
)
// SystemBannerManager is a structure containing all system banner manager members.
type SystemBannerManager struct {
systemBanner api.SystemBanner
}
// NewSystemBannerManager creates new settings manager.
func NewSystemBannerManager(message, severity string) SystemBannerManager {
return SystemBannerManager{
systemBanner: api.SystemBanner{
Message: message,
Severity: api.GetSeverity(severity),
},
}
}
// Get implements SystemBannerManager interface. Check it for more information.
func (sbm *SystemBannerManager) Get() api.SystemBanner {
return sbm.systemBanner
}
...@@ -1553,3 +1553,11 @@ backendApi.SupportedAuthenticationModes; ...@@ -1553,3 +1553,11 @@ backendApi.SupportedAuthenticationModes;
* }} * }}
*/ */
backendApi.Status; backendApi.Status;
/**
* @typedef {{
* message: string,
* severity: string
* }}
*/
backendApi.SystemBanner;
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// Function
//-- Must be defined before variables
@function rem($multiplier) { @function rem($multiplier) {
$font-size: 10px; $font-size: 10px;
@return $multiplier * $font-size; @return $multiplier * $font-size;
...@@ -50,16 +48,11 @@ $emphasis: #000; ...@@ -50,16 +48,11 @@ $emphasis: #000;
$content-background: #fff; $content-background: #fff;
$chart-1: #00c752; $chart-1: #00c752;
$chart-2: #326de6; $chart-2: #326de6;
// Resource state chart colors
$failed-resource-color: #f00; $failed-resource-color: #f00;
$running-resource-color: #00c752; $running-resource-color: #00c752;
$pending-resource-color: #ff0; $pending-resource-color: #ff0;
$success-color: #008000; $success-color: #008000;
$error-color: #ff5722; $error-color: #ff5722;
// TODO(bryk): Get those variables from Angular Material scss files.
$foreground-1: rgba(0, 0, 0, .87); $foreground-1: rgba(0, 0, 0, .87);
$foreground-2: rgba(0, 0, 0, .54); $foreground-2: rgba(0, 0, 0, .54);
$foreground-3: rgba(0, 0, 0, .38); $foreground-3: rgba(0, 0, 0, .38);
...@@ -68,7 +61,6 @@ $hue-1: rgba(255, 255, 255, .87); ...@@ -68,7 +61,6 @@ $hue-1: rgba(255, 255, 255, .87);
$hue-2: rgba(255, 255, 255, .54); $hue-2: rgba(255, 255, 255, .54);
$hue-3: rgba(255, 255, 255, .26); $hue-3: rgba(255, 255, 255, .26);
$hue-4: rgba(255, 255, 255, .12); $hue-4: rgba(255, 255, 255, .12);
$background-1: rgba(158, 158, 158, .2); $background-1: rgba(158, 158, 158, .2);
$background-2: rgba(226, 226, 226, .2); $background-2: rgba(226, 226, 226, .2);
$overlay-color: $hue-2; $overlay-color: $hue-2;
......
...@@ -58,6 +58,12 @@ limitations under the License. ...@@ -58,6 +58,12 @@ limitations under the License.
</div> </div>
</md-toolbar> </md-toolbar>
<md-toolbar class="kd-system-banner"
ng-class="$ctrl.getSystemBannerClass()"
ng-if="$ctrl.isSystemBannerVisible()"
ng-bind-html="$ctrl.getSystemBannerMessage()">
</md-toolbar>
<md-content layout="row" <md-content layout="row"
class="kd-app-entire-content" class="kd-app-entire-content"
flex="auto"> flex="auto">
......
...@@ -66,6 +66,28 @@ kd-chrome { ...@@ -66,6 +66,28 @@ kd-chrome {
margin-top: .6 * $baseline-grid; margin-top: .6 * $baseline-grid;
} }
} }
.kd-system-banner {
background-color: $running-resource-color;
box-shadow: $whiteframe-shadow-1dp;
color: $foreground-1;
display: inline;
font-size: $body-font-size-base;
height: 6 * $baseline-grid;
line-height: 6 * $baseline-grid;
min-height: 6 * $baseline-grid;
overflow: hidden;
padding: 0 (3 * $baseline-grid);
white-space: nowrap;
}
.kd-system-banner-error {
background-color: $error-color;
}
.kd-system-banner-warning {
background-color: $warning;
}
} }
.kd-second-toolbar { .kd-second-toolbar {
......
...@@ -27,9 +27,11 @@ export class ChromeController { ...@@ -27,9 +27,11 @@ export class ChromeController {
* @param {!ui.router.$state} $state * @param {!ui.router.$state} $state
* @param {!angular.$timeout} $timeout * @param {!angular.$timeout} $timeout
* @param {!kdUiRouter.$transitions} $transitions * @param {!kdUiRouter.$transitions} $transitions
* @param {!angular.$resource} $resource
* @param {!angular.$sce} $sce
* @ngInject * @ngInject
*/ */
constructor($state, $timeout, $transitions) { constructor($state, $timeout, $transitions, $resource, $sce) {
/** /**
* By default this is true to show loading spinner for the first page. * By default this is true to show loading spinner for the first page.
* @export {boolean} * @export {boolean}
...@@ -50,11 +52,60 @@ export class ChromeController { ...@@ -50,11 +52,60 @@ export class ChromeController {
/** @private {!kdUiRouter.$transitions} */ /** @private {!kdUiRouter.$transitions} */
this.transitions_ = $transitions; this.transitions_ = $transitions;
/** @private {!angular.$resource} */
this.resource_ = $resource;
/** @private {!angular.$sce} */
this.sce_ = $sce;
/** @private {!backendApi.SystemBanner} */
this.systemBanner_;
} }
/** @export */ /** @export */
$onInit() { $onInit() {
this.registerStateChangeListeners(); this.registerStateChangeListeners();
this.initSystemBanner_();
}
/**
* @private
*/
initSystemBanner_() {
this.resource_('api/v1/systembanner').get((sb) => {
this.systemBanner_ = sb;
});
}
/**
* @export
* @return {boolean}
*/
isSystemBannerVisible() {
return this.systemBanner_ !== undefined && this.systemBanner_.message.length > 0;
}
/**
* @export
* @return {string}
*/
getSystemBannerClass() {
if (this.systemBanner_ && this.systemBanner_.severity) {
return `kd-system-banner-${this.systemBanner_.severity.toLowerCase()}`;
}
return '';
}
/**
* @export
* @return {*}
*/
getSystemBannerMessage() {
if (this.isSystemBannerVisible()) {
return this.sce_.trustAsHtml(this.systemBanner_.message);
}
return '';
} }
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册