mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
Adding deployment-replication dashboard
This commit is contained in:
parent
995975f20f
commit
1f4cfbf5eb
12 changed files with 560 additions and 52 deletions
File diff suppressed because one or more lines are too long
|
@ -16,7 +16,7 @@
|
|||
"devDependencies": {
|
||||
"react-scripts": "1.1.4"
|
||||
},
|
||||
"proxy": "https://192.168.140.211:8528",
|
||||
"proxy": "https://192.168.140.212:8528",
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React, { Component } from 'react';
|
||||
import ReactTimeout from 'react-timeout';
|
||||
import DeploymentOperator from './deployment/DeploymentOperator.js';
|
||||
import StorageOperator from './storage/StorageOperator.js';
|
||||
import NoOperator from './NoOperator.js';
|
||||
import Loading from './util/Loading.js';
|
||||
import api, { IsUnauthorized } from './api/api.js';
|
||||
import DeploymentOperator from './deployment/DeploymentOperator';
|
||||
import DeploymentReplicationOperator from './replication/DeploymentReplicationOperator';
|
||||
import StorageOperator from './storage/StorageOperator';
|
||||
import NoOperator from './NoOperator';
|
||||
import Loading from './util/Loading';
|
||||
import api, { IsUnauthorized } from './api/api';
|
||||
import { Container, Segment, Message } from 'semantic-ui-react';
|
||||
import { withAuth } from './auth/Auth.js';
|
||||
import { withAuth } from './auth/Auth';
|
||||
|
||||
const PodInfoView = ({pod, namespace}) => (
|
||||
<Segment basic>
|
||||
|
@ -17,11 +18,14 @@ const PodInfoView = ({pod, namespace}) => (
|
|||
</Segment>
|
||||
);
|
||||
|
||||
const OperatorsView = ({error, deployment, storage, pod, namespace}) => {
|
||||
const OperatorsView = ({error, deployment, deploymentReplication, storage, pod, namespace}) => {
|
||||
const podInfoView = (<PodInfoView pod={pod} namespace={namespace}/>);
|
||||
if (deployment) {
|
||||
return (<DeploymentOperator podInfoView={podInfoView} error={error}/>);
|
||||
}
|
||||
if (deploymentReplication) {
|
||||
return (<DeploymentReplicationOperator podInfoView={podInfoView} error={error}/>);
|
||||
}
|
||||
if (storage) {
|
||||
return (<StorageOperator podInfoView={podInfoView} error={error}/>);
|
||||
}
|
||||
|
@ -67,6 +71,7 @@ class App extends Component {
|
|||
return <OperatorsView
|
||||
error={this.state.error}
|
||||
deployment={this.state.operators.deployment}
|
||||
deploymentReplication={this.state.operators.deployment_replication}
|
||||
storage={this.state.operators.storage}
|
||||
pod={this.state.operators.pod}
|
||||
namespace={this.state.operators.namespace}
|
||||
|
|
67
dashboard/src/replication/DeploymentReplicationDetails.js
Normal file
67
dashboard/src/replication/DeploymentReplicationDetails.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
import ReactTimeout from 'react-timeout';
|
||||
import React, { Component } from 'react';
|
||||
import api, { IsUnauthorized } from '../api/api.js';
|
||||
import Loading from '../util/Loading.js';
|
||||
import styled from 'react-emotion';
|
||||
import { Loader } from 'semantic-ui-react';
|
||||
import { withAuth } from '../auth/Auth.js';
|
||||
|
||||
const LoaderBox = styled('span')`
|
||||
float: right;
|
||||
width: 0;
|
||||
padding-right: 1em;
|
||||
margin-right: 1em;
|
||||
margin-top: 1em;
|
||||
max-width: 0;
|
||||
display: inline-block;
|
||||
`;
|
||||
|
||||
class DeploymentReplicationDetails extends Component {
|
||||
state = {
|
||||
loading: true,
|
||||
error: undefined
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.reloadDeploymentReplications();
|
||||
}
|
||||
|
||||
reloadDeploymentReplications = async() => {
|
||||
try {
|
||||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
const result = await api.get(`/api/deployment-replication/${this.props.name}`);
|
||||
this.setState({
|
||||
replication: result,
|
||||
loading: false,
|
||||
error: undefined
|
||||
});
|
||||
} catch (e) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
error: e.message
|
||||
});
|
||||
if (IsUnauthorized(e)) {
|
||||
this.props.doLogout();
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.props.setTimeout(this.reloadDeploymentReplications, 5000);
|
||||
}
|
||||
|
||||
render() {
|
||||
const dr = this.state.replication;
|
||||
if (!dr) {
|
||||
return (<Loading/>);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<LoaderBox><Loader size="mini" active={this.state.loading} inline/></LoaderBox>
|
||||
<div>TODO</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ReactTimeout(withAuth(DeploymentReplicationDetails));
|
147
dashboard/src/replication/DeploymentReplicationList.js
Normal file
147
dashboard/src/replication/DeploymentReplicationList.js
Normal file
|
@ -0,0 +1,147 @@
|
|||
import { Icon, Loader, Popup, Table } from 'semantic-ui-react';
|
||||
import { Link } from "react-router-dom";
|
||||
import api, { IsUnauthorized } from '../api/api.js';
|
||||
import CommandInstruction from '../util/CommandInstruction.js';
|
||||
import Loading from '../util/Loading.js';
|
||||
import React, { Component } from 'react';
|
||||
import ReactTimeout from 'react-timeout';
|
||||
import styled from 'react-emotion';
|
||||
import { withAuth } from '../auth/Auth.js';
|
||||
|
||||
const LoaderBox = styled('span')`
|
||||
float: right;
|
||||
width: 0;
|
||||
padding-right: 1em;
|
||||
max-width: 0;
|
||||
display: inline-block;
|
||||
`;
|
||||
|
||||
const HeaderView = ({loading}) => (
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>State</Table.HeaderCell>
|
||||
<Table.HeaderCell>Name</Table.HeaderCell>
|
||||
<Table.HeaderCell>
|
||||
Actions
|
||||
<LoaderBox><Loader size="mini" active={loading} inline/></LoaderBox>
|
||||
</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
);
|
||||
|
||||
const RowView = ({name, mode, stateColor, deleteCommand, describeCommand}) => (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Popup trigger={<Icon name={(stateColor==="green") ? "check" : "bell"} color={stateColor}/>}>
|
||||
{getStateColorDescription(stateColor)}
|
||||
</Popup>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Link to={`/deployment-replication/${name}`}>
|
||||
{name}
|
||||
</Link>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<CommandInstruction
|
||||
trigger={<Icon link name="zoom"/>}
|
||||
command={describeCommand}
|
||||
title="Describe deployment replication"
|
||||
description="To get more information on the state of this deployment replication, run:"
|
||||
/>
|
||||
<span style={{"float":"right"}}>
|
||||
<CommandInstruction
|
||||
trigger={<Icon link name="trash"/>}
|
||||
command={deleteCommand}
|
||||
title="Delete deployment replication"
|
||||
description="To delete this deployment replication, run:"
|
||||
/>
|
||||
</span>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
|
||||
const ListView = ({items, loading}) => (
|
||||
<Table striped celled>
|
||||
<HeaderView loading={loading}/>
|
||||
<Table.Body>
|
||||
{
|
||||
(items) ? items.map((item) =>
|
||||
<RowView
|
||||
key={item.name}
|
||||
name={item.name}
|
||||
namespace={item.namespace}
|
||||
stateColor={item.state_color}
|
||||
deleteCommand={createDeleteCommand(item.name, item.namespace)}
|
||||
describeCommand={createDescribeCommand(item.name, item.namespace)}
|
||||
/>) : <p>No items</p>
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
);
|
||||
|
||||
const EmptyView = () => (<div>No deployment replications</div>);
|
||||
|
||||
function createDeleteCommand(name, namespace) {
|
||||
return `kubectl delete ArangoDeploymentReplication -n ${namespace} ${name}`;
|
||||
}
|
||||
|
||||
function createDescribeCommand(name, namespace) {
|
||||
return `kubectl describe ArangoDeploymentReplication -n ${namespace} ${name}`;
|
||||
}
|
||||
|
||||
function getStateColorDescription(stateColor) {
|
||||
switch (stateColor) {
|
||||
case "green":
|
||||
return "Replication has been configured.";
|
||||
case "yellow":
|
||||
return "Replication is being configured.";
|
||||
case "red":
|
||||
return "The replication is in a bad state and manual intervention is likely needed.";
|
||||
default:
|
||||
return "State is not known.";
|
||||
}
|
||||
}
|
||||
|
||||
class DeploymentReplicationList extends Component {
|
||||
state = {
|
||||
items: null,
|
||||
error: null,
|
||||
loading: true
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.reloadDeploymentReplications();
|
||||
}
|
||||
|
||||
reloadDeploymentReplications = async() => {
|
||||
try {
|
||||
this.setState({loading: true});
|
||||
const result = await api.get('/api/deployment-replication');
|
||||
this.setState({
|
||||
items: result.replications,
|
||||
loading: false,
|
||||
error: null
|
||||
});
|
||||
} catch (e) {
|
||||
this.setState({error: e.message, loading: false});
|
||||
if (IsUnauthorized(e)) {
|
||||
this.props.doLogout();
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.props.setTimeout(this.reloadDeploymentReplications, 5000);
|
||||
}
|
||||
|
||||
render() {
|
||||
const items = this.state.items;
|
||||
if (!items) {
|
||||
return (<Loading/>);
|
||||
}
|
||||
if (items.length === 0) {
|
||||
return (<EmptyView/>);
|
||||
}
|
||||
return (<ListView items={items} loading={this.state.loading}/>);
|
||||
}
|
||||
}
|
||||
|
||||
export default ReactTimeout(withAuth(DeploymentReplicationList));
|
74
dashboard/src/replication/DeploymentReplicationOperator.js
Normal file
74
dashboard/src/replication/DeploymentReplicationOperator.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
import React, { Component } from 'react';
|
||||
import LogoutContext from '../auth/LogoutContext.js';
|
||||
import DeploymentReplicationDetails from './DeploymentReplicationDetails.js';
|
||||
import DeploymentReplicationList from './DeploymentReplicationList.js';
|
||||
import { Header, Menu, Message, Segment } from 'semantic-ui-react';
|
||||
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
|
||||
import styled from 'react-emotion';
|
||||
|
||||
const StyledMenu = styled(Menu)`
|
||||
width: 15rem !important;
|
||||
@media (max-width: 768px) {
|
||||
width: 10rem !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledContentBox = styled('div')`
|
||||
margin-left: 15rem;
|
||||
@media (max-width: 768px) {
|
||||
margin-left: 10rem;
|
||||
}
|
||||
`;
|
||||
|
||||
const ListView = () => (
|
||||
<div>
|
||||
<Header dividing>
|
||||
ArangoDeploymentReplication resources
|
||||
</Header>
|
||||
<DeploymentReplicationList/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const DetailView = ({match}) => (
|
||||
<div>
|
||||
<Header dividing>
|
||||
ArangoDeploymentReplication {match.params.name}
|
||||
</Header>
|
||||
<DeploymentReplicationDetails name={match.params.name}/>
|
||||
</div>
|
||||
);
|
||||
|
||||
class DeploymentReplicationOperator extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Router>
|
||||
<div>
|
||||
<LogoutContext.Consumer>
|
||||
{doLogout =>
|
||||
<StyledMenu fixed="left" vertical>
|
||||
<Menu.Item>
|
||||
<Link to="/">Deployment replications</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item position="right" onClick={() => doLogout()}>
|
||||
Logout
|
||||
</Menu.Item>
|
||||
</StyledMenu>
|
||||
}
|
||||
</LogoutContext.Consumer>
|
||||
<StyledContentBox>
|
||||
<Segment basic clearing>
|
||||
<div>
|
||||
<Route exact path="/" component={ListView} />
|
||||
<Route path="/deployment-replication/:name" component={DetailView} />
|
||||
</div>
|
||||
</Segment>
|
||||
{this.props.podInfoView}
|
||||
{(this.props.error) ? <Segment basic><Message error content={this.props.error}/></Segment> : null}
|
||||
</StyledContentBox>
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DeploymentReplicationOperator;
|
19
manifests/templates/deployment-replication/service.yaml
Normal file
19
manifests/templates/deployment-replication/service.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .DeploymentReplication.OperatorDeploymentName }}
|
||||
namespace: {{ .DeploymentReplication.Operator.Namespace }}
|
||||
labels:
|
||||
name: {{ .DeploymentReplication.OperatorDeploymentName }}
|
||||
app: arango-deployment-replication-operator
|
||||
spec:
|
||||
ports:
|
||||
- name: server
|
||||
port: 8528
|
||||
protocol: TCP
|
||||
targetPort: 8528
|
||||
selector:
|
||||
name: {{ .DeploymentReplication.OperatorDeploymentName }}
|
||||
app: arango-deployment-replication-operator
|
||||
role: leader
|
||||
type: {{ .DeploymentReplication.Operator.ServiceType }}
|
|
@ -61,6 +61,39 @@ func (o *Operator) GetDeployment(name string) (server.Deployment, error) {
|
|||
return nil, maskAny(server.NotFoundError)
|
||||
}
|
||||
|
||||
// DeploymentReplicationOperator provides access to the deployment replication operator.
|
||||
func (o *Operator) DeploymentReplicationOperator() server.DeploymentReplicationOperator {
|
||||
return o
|
||||
}
|
||||
|
||||
// GetDeploymentReplications returns all current deployments
|
||||
func (o *Operator) GetDeploymentReplications() ([]server.DeploymentReplication, error) {
|
||||
o.Dependencies.LivenessProbe.Lock()
|
||||
defer o.Dependencies.LivenessProbe.Unlock()
|
||||
|
||||
result := make([]server.DeploymentReplication, 0, len(o.deploymentReplications))
|
||||
for _, d := range o.deploymentReplications {
|
||||
result = append(result, d)
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
return result[i].Name() < result[j].Name()
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetDeploymentReplication returns detailed information for a deployment replication, managed by the operator, with given name
|
||||
func (o *Operator) GetDeploymentReplication(name string) (server.DeploymentReplication, error) {
|
||||
o.Dependencies.LivenessProbe.Lock()
|
||||
defer o.Dependencies.LivenessProbe.Unlock()
|
||||
|
||||
for _, d := range o.deploymentReplications {
|
||||
if d.Name() == name {
|
||||
return d, nil
|
||||
}
|
||||
}
|
||||
return nil, maskAny(server.NotFoundError)
|
||||
}
|
||||
|
||||
// StorageOperator provides the local storage operator (if any)
|
||||
func (o *Operator) StorageOperator() server.StorageOperator {
|
||||
return o
|
||||
|
|
50
pkg/replication/server_api.go
Normal file
50
pkg/replication/server_api.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// Author Ewout Prangsma
|
||||
//
|
||||
|
||||
package replication
|
||||
|
||||
import (
|
||||
api "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1alpha"
|
||||
"github.com/arangodb/kube-arangodb/pkg/server"
|
||||
)
|
||||
|
||||
// Name returns the name of the deployment.
|
||||
func (dr *DeploymentReplication) Name() string {
|
||||
return dr.apiObject.Name
|
||||
}
|
||||
|
||||
// Namespace returns the namespace that contains the deployment.
|
||||
func (dr *DeploymentReplication) Namespace() string {
|
||||
return dr.apiObject.Namespace
|
||||
}
|
||||
|
||||
// StateColor determinates the state of the deployment in color codes.
|
||||
func (dr *DeploymentReplication) StateColor() server.StateColor {
|
||||
switch dr.status.Phase {
|
||||
case api.DeploymentReplicationPhaseFailed:
|
||||
return server.StateRed
|
||||
}
|
||||
if dr.status.Conditions.IsTrue(api.ConditionTypeConfigured) {
|
||||
return server.StateGreen
|
||||
}
|
||||
return server.StateYellow
|
||||
}
|
106
pkg/server/handlers_replication.go
Normal file
106
pkg/server/handlers_replication.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// Author Ewout Prangsma
|
||||
//
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DeploymentReplication is the API implemented by an ArangoDeploymentReplication.
|
||||
type DeploymentReplication interface {
|
||||
Name() string
|
||||
Namespace() string
|
||||
StateColor() StateColor
|
||||
}
|
||||
|
||||
// DeploymentReplicationOperator is the API implemented by the deployment operator.
|
||||
type DeploymentReplicationOperator interface {
|
||||
// GetDeploymentReplications returns basic information for all deployment replications managed by the operator
|
||||
GetDeploymentReplications() ([]DeploymentReplication, error)
|
||||
// GetDeploymentReplication returns detailed information for a deployment replication, managed by the operator, with given name
|
||||
GetDeploymentReplication(name string) (DeploymentReplication, error)
|
||||
}
|
||||
|
||||
// DeploymentReplicationInfo is the information returned per deployment replication.
|
||||
type DeploymentReplicationInfo struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
StateColor StateColor `json:"state_color"`
|
||||
}
|
||||
|
||||
// newDeploymentReplicationInfo initializes a DeploymentReplicationInfo for the given deployment replication.
|
||||
func newDeploymentReplicationInfo(dr DeploymentReplication) DeploymentReplicationInfo {
|
||||
return DeploymentReplicationInfo{
|
||||
Name: dr.Name(),
|
||||
Namespace: dr.Namespace(),
|
||||
StateColor: dr.StateColor(),
|
||||
}
|
||||
}
|
||||
|
||||
// DeploymentReplicationInfoDetails is the detailed information returned per deployment replication.
|
||||
type DeploymentReplicationInfoDetails struct {
|
||||
DeploymentReplicationInfo
|
||||
}
|
||||
|
||||
// newDeploymentReplicationInfoDetails initializes a DeploymentReplicationInfoDetails for the given deployment replication.
|
||||
func newDeploymentReplicationInfoDetails(dr DeploymentReplication) DeploymentReplicationInfoDetails {
|
||||
result := DeploymentReplicationInfoDetails{
|
||||
DeploymentReplicationInfo: newDeploymentReplicationInfo(dr),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Handle a GET /api/deployment-replication request
|
||||
func (s *Server) handleGetDeploymentReplications(c *gin.Context) {
|
||||
if do := s.deps.Operators.DeploymentReplicationOperator(); do != nil {
|
||||
// Fetch deployment replications
|
||||
repls, err := do.GetDeploymentReplications()
|
||||
if err != nil {
|
||||
sendError(c, err)
|
||||
} else {
|
||||
result := make([]DeploymentReplicationInfo, len(repls))
|
||||
for i, dr := range repls {
|
||||
result[i] = newDeploymentReplicationInfo(dr)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"replications": result,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle a GET /api/deployment-replication/:name request
|
||||
func (s *Server) handleGetDeploymentReplicationDetails(c *gin.Context) {
|
||||
if do := s.deps.Operators.DeploymentReplicationOperator(); do != nil {
|
||||
// Fetch deployments
|
||||
dr, err := do.GetDeploymentReplication(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
sendError(c, err)
|
||||
} else {
|
||||
result := newDeploymentReplicationInfoDetails(dr)
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,6 +69,8 @@ type Dependencies struct {
|
|||
type Operators interface {
|
||||
// Return the deployment operator (if any)
|
||||
DeploymentOperator() DeploymentOperator
|
||||
// Return the deployment replication operator (if any)
|
||||
DeploymentReplicationOperator() DeploymentReplicationOperator
|
||||
// Return the local storage operator (if any)
|
||||
StorageOperator() StorageOperator
|
||||
}
|
||||
|
@ -156,6 +158,10 @@ func NewServer(cli corev1.CoreV1Interface, cfg Config, deps Dependencies) (*Serv
|
|||
api.GET("/deployment", s.handleGetDeployments)
|
||||
api.GET("/deployment/:name", s.handleGetDeploymentDetails)
|
||||
|
||||
// Deployment replication operator
|
||||
api.GET("/deployment-replication", s.handleGetDeploymentReplications)
|
||||
api.GET("/deployment-replication/:name", s.handleGetDeploymentReplicationDetails)
|
||||
|
||||
// Local storage operator
|
||||
api.GET("/storage", s.handleGetLocalStorages)
|
||||
api.GET("/storage/:name", s.handleGetLocalStorageDetails)
|
||||
|
|
|
@ -59,6 +59,7 @@ var (
|
|||
deploymentReplicationTemplateNames = []string{
|
||||
"rbac.yaml",
|
||||
"deployment-replication.yaml",
|
||||
"service.yaml",
|
||||
}
|
||||
storageTemplateNames = []string{
|
||||
"rbac.yaml",
|
||||
|
|
Loading…
Reference in a new issue