Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add links to other operators in dashboard menu #217

Merged
merged 2 commits into from
Jul 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 49 additions & 49 deletions dashboard/assets.go

Large diffs are not rendered by default.

26 changes: 24 additions & 2 deletions dashboard/src/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Container, Segment, Message } from 'semantic-ui-react';
import { Container, Segment, Menu, Message } from 'semantic-ui-react';
import React, { Component } from 'react';
import ReactTimeout from 'react-timeout';

Expand All @@ -19,7 +19,14 @@ const PodInfoView = ({pod, namespace}) => (
</Segment>
);

const OperatorsView = ({error, deployment, deploymentReplication, storage, pod, namespace}) => {
const OperatorsView = ({error, deployment, deploymentReplication, storage, pod, namespace, otherOperators}) => {
let commonMenuItems = otherOperators.map((item) => <Menu.Item><a href={item.url}>{operatorType2Name(item.type)}</a></Menu.Item>);
if (commonMenuItems.length > 0) {
commonMenuItems = (<Menu.Item>
<Menu.Header>Other operators</Menu.Header>
<Menu.Menu>{commonMenuItems}</Menu.Menu>
</Menu.Item>);
}
let Operator = NoOperator;
if (deployment)
Operator = DeploymentOperator;
Expand All @@ -30,11 +37,25 @@ const OperatorsView = ({error, deployment, deploymentReplication, storage, pod,
return (
<Operator
podInfoView={<PodInfoView pod={pod} namespace={namespace} />}
commonMenuItems={commonMenuItems}
error={error}
/>
);
}

const operatorType2Name = (oType) => {
switch (oType) {
case "deployment":
return "Deployments";
case "deployment_replication":
return "Deployment replications";
case "storage":
return "Storage";
default:
return "";
}
};

const LoadingView = () => (
<Container>
<Loading/>
Expand Down Expand Up @@ -76,6 +97,7 @@ class App extends Component {
deployment={this.state.operators.deployment}
deploymentReplication={this.state.operators.deployment_replication}
storage={this.state.operators.storage}
otherOperators={this.state.operators.other || []}
pod={this.state.operators.pod}
namespace={this.state.operators.namespace}
/>;
Expand Down
14 changes: 10 additions & 4 deletions dashboard/src/deployment/DeploymentOperator.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,16 @@ class DeploymentOperator extends Component {
{doLogout =>
<StyledMenu fixed="left" vertical>
<Menu.Item>
<Link to="/">Deployments</Link>
</Menu.Item>
<Menu.Item position="right" onClick={() => doLogout()}>
Logout
<Menu.Header>Deployment Operator</Menu.Header>
<Menu.Menu>
<Menu.Item>
<Link to="/">Deployments</Link>
</Menu.Item>
<Menu.Item position="right" onClick={() => doLogout()}>
Logout
</Menu.Item>
</Menu.Menu>
{this.props.commonMenuItems}
</Menu.Item>
</StyledMenu>
}
Expand Down
14 changes: 10 additions & 4 deletions dashboard/src/replication/DeploymentReplicationOperator.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,17 @@ class DeploymentReplicationOperator extends Component {
{doLogout =>
<StyledMenu fixed="left" vertical>
<Menu.Item>
<Link to="/">Deployment replications</Link>
</Menu.Item>
<Menu.Item position="right" onClick={() => doLogout()}>
Logout
<Menu.Header>Deployment Replication Operator</Menu.Header>
<Menu.Menu>
<Menu.Item>
<Link to="/">Deployment replications</Link>
</Menu.Item>
<Menu.Item position="right" onClick={() => doLogout()}>
Logout
</Menu.Item>
</Menu.Menu>
</Menu.Item>
{this.props.commonMenuItems}
</StyledMenu>
}
</LogoutContext.Consumer>
Expand Down
18 changes: 12 additions & 6 deletions dashboard/src/storage/StorageOperator.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@ class StorageOperator extends Component {
<div>
<LogoutContext.Consumer>
{doLogout =>
<StyledMenu fixed="left" vertical>
<StyledMenu fixed="left" vertical>
<Menu.Item>
Local storages
<Menu.Header>Deployment Operator</Menu.Header>
<Menu.Menu>
<Menu.Item>
Local storages
</Menu.Item>
<Menu.Item position="right" onClick={() => doLogout()}>
Logout
</Menu.Item>
</Menu.Menu>
{this.props.commonMenuItems}
</Menu.Item>
<Menu.Item position="right" onClick={() => doLogout()}>
Logout
</Menu.Item>
</StyledMenu>
</StyledMenu>
}
</LogoutContext.Consumer>
<StyledContentBox>
Expand Down
4 changes: 2 additions & 2 deletions manifests/templates/deployment-replication/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ rules:
resources: ["pods", "services", "endpoints", "persistentvolumeclaims", "events", "secrets"]
verbs: ["*"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get"]
resources: ["namespaces", "nodes"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get"]
Expand Down
4 changes: 2 additions & 2 deletions manifests/templates/deployment/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ rules:
resources: ["pods", "services", "endpoints", "persistentvolumeclaims", "events", "secrets"]
verbs: ["*"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get"]
resources: ["namespaces", "nodes"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get"]
Expand Down
3 changes: 3 additions & 0 deletions manifests/templates/storage/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
- apiGroups: [""]
resources: ["namespaces", "nodes"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["daemonsets"]
verbs: ["*"]
Expand Down
36 changes: 15 additions & 21 deletions pkg/deployment/server_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@
package deployment

import (
"fmt"
"net"
"sort"
"strconv"

"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -197,28 +194,25 @@ func (d *Deployment) DatabaseURL() string {
if err != nil {
return ""
}
host := ""
switch svc.Spec.Type {
case v1.ServiceTypeLoadBalancer:
for _, i := range svc.Status.LoadBalancer.Ingress {
if i.Hostname != "" {
host = i.Hostname
} else {
host = i.IP
}
break
}
case v1.ServiceTypeNodePort:
// TODO
}
if host == "" {
return ""
}
scheme := "https"
if !d.GetSpec().IsSecure() {
scheme = "http"
}
return fmt.Sprintf("%s://%s", scheme, net.JoinHostPort(host, strconv.Itoa(k8sutil.ArangoPort)))
nodeFetcher := func() (v1.NodeList, error) {
result, err := d.deps.KubeCli.CoreV1().Nodes().List(metav1.ListOptions{})
if err != nil {
return v1.NodeList{}, maskAny(err)
}
return *result, nil
}
portPredicate := func(p v1.ServicePort) bool {
return p.TargetPort.IntValue() == k8sutil.ArangoPort
}
url, err := k8sutil.CreateServiceURL(*svc, scheme, portPredicate, nodeFetcher)
if err != nil {
return ""
}
return url
}

// DatabaseVersion returns the version used by the deployment
Expand Down
4 changes: 2 additions & 2 deletions pkg/logging/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ var (
// The defaultLevels list is used during development to increase the
// default level for components that we care a little less about.
defaultLevels = map[string]string{
"operator": "info",
//"something.status": "info",
//"operator": "info",
//"something.status": "info",
}
)

Expand Down
146 changes: 146 additions & 0 deletions pkg/operator/server_discovery_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//
// 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 operator

import (
"sort"

"github.com/rs/zerolog"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/arangodb/kube-arangodb/pkg/server"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
)

const (
appKey = "app"
roleKey = "role"
appDeploymentOperator = "arango-deployment-operator"
appDeploymentReplicationOperator = "arango-deployment-replication-operator"
appStorageOperator = "arango-storage-operator"
roleLeader = "leader"
)

// FindOtherOperators looks up references to other operators in the same Kubernetes cluster.
func (o *Operator) FindOtherOperators() []server.OperatorReference {
log := o.log
var result []server.OperatorReference
namespaces, err := o.Dependencies.KubeCli.CoreV1().Namespaces().List(metav1.ListOptions{})
if err != nil {
log.Warn().Err(err).Msg("Failed to list namespaces")
} else {
for _, ns := range namespaces.Items {
if ns.Name != o.Config.Namespace {
log.Debug().Str("namespace", ns.Name).Msg("inspecting namespace for operators")
refs := o.findOtherOperatorsInNamespace(log, ns.Name, func(server.OperatorType) bool { return true })
result = append(result, refs...)
} else {
log.Debug().Str("namespace", ns.Name).Msg("skip inspecting my own namespace for operators")
}
}
}
refs := o.findOtherOperatorsInNamespace(log, o.Config.Namespace, func(oType server.OperatorType) bool {
// Exclude those operators that I provide myself.
switch oType {
case server.OperatorTypeDeployment:
return !o.Dependencies.DeploymentProbe.IsReady()
case server.OperatorTypeDeploymentReplication:
return !o.Dependencies.DeploymentReplicationProbe.IsReady()
case server.OperatorTypeStorage:
return !o.Dependencies.StorageProbe.IsReady()
default:
return true
}
})
result = append(result, refs...)
sort.Slice(result, func(i, j int) bool {
if result[i].Namespace == result[j].Namespace {
return result[i].Type < result[j].Type
}
return result[i].Namespace < result[j].Namespace
})

return result
}

// findOtherOperatorsInNamespace looks up references to other operators in the given namespace.
func (o *Operator) findOtherOperatorsInNamespace(log zerolog.Logger, namespace string, typePred func(server.OperatorType) bool) []server.OperatorReference {
log = log.With().Str("namespace", namespace).Logger()
var result []server.OperatorReference
services, err := o.Dependencies.KubeCli.CoreV1().Services(namespace).List(metav1.ListOptions{})
if err != nil {
log.Debug().Err(err).Msg("Failed to list services")
return nil
}
nodeFetcher := func() (v1.NodeList, error) {
result, err := o.Dependencies.KubeCli.CoreV1().Nodes().List(metav1.ListOptions{})
if err != nil {
return v1.NodeList{}, maskAny(err)
}
return *result, nil
}
for _, svc := range services.Items {
// Filter out unwanted services
selector := svc.Spec.Selector
if selector[roleKey] != roleLeader {
log.Debug().Str("service", svc.Name).Msg("Service has no leader role selector")
continue
}
var oType server.OperatorType
switch selector[appKey] {
case appDeploymentOperator:
oType = server.OperatorTypeDeployment
case appDeploymentReplicationOperator:
oType = server.OperatorTypeDeploymentReplication
case appStorageOperator:
oType = server.OperatorTypeStorage
default:
log.Debug().Str("service", svc.Name).Msg("Service has no or invalid app selector")
continue
}
if !typePred(oType) {
continue
}
var url string
switch svc.Spec.Type {
case v1.ServiceTypeNodePort, v1.ServiceTypeLoadBalancer:
if x, err := k8sutil.CreateServiceURL(svc, "https", nil, nodeFetcher); err == nil {
url = x
} else {
log.Warn().Err(err).Str("service", svc.Name).Msg("Failed to create URL for service")
}
default:
// No suitable service type
continue
}
result = append(result, server.OperatorReference{
Namespace: svc.GetNamespace(),
URL: url,
Type: oType,
})
}

log.Debug().Msgf("Found %d operator services", len(result))
return result
}
Loading