Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan
- [#88](https://github.com/kobsio/kobs/pull/88): Improve handling of actions for Kubernetes resources.
- [#95](https://github.com/kobsio/kobs/pull/95): It is now possible to get Kubernetes resources for all namespaces by not selecting a namespace from the select box on the resources page.
- [#96](https://github.com/kobsio/kobs/pull/96): Add RSS plugin to show the latest status updates of third party services.
- [#101](https://github.com/kobsio/kobs/pull/101): Show logs in the terminal.

## [v0.4.0](https://github.com/kobsio/kobs/releases/tag/v0.4.0) (2021-07-14)

Expand Down
35 changes: 31 additions & 4 deletions pkg/api/clusters/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,17 +196,44 @@ func (c *Cluster) CreateResource(ctx context.Context, namespace, name, path, res
// GetLogs returns the logs for a Container. The Container is identified by the namespace and pod name and the container
// name. Is is also possible to set the time since when the logs should be received and with the previous flag the logs
// for the last container can be received.
func (c *Cluster) GetLogs(ctx context.Context, namespace, name, container string, since int64, previous bool) (string, error) {
res, err := c.clientset.CoreV1().Pods(namespace).GetLogs(name, &corev1.PodLogOptions{
func (c *Cluster) GetLogs(ctx context.Context, namespace, name, container, regex string, since, tail int64, previous bool) (string, error) {
options := &corev1.PodLogOptions{
Container: container,
SinceSeconds: &since,
Previous: previous,
}).DoRaw(ctx)
}

if tail > 0 {
options.TailLines = &tail
}

res, err := c.clientset.CoreV1().Pods(namespace).GetLogs(name, options).DoRaw(ctx)
if err != nil {
return "", err
}

return string(res), nil
if regex == "" {
var logs []string
for _, line := range strings.Split(string(res), "\n") {
logs = append(logs, line)
}

return strings.Join(logs, "\n\r") + "\n\r", nil
}

reg, err := regexp.Compile(regex)
if err != nil {
return "", err
}

var logs []string
for _, line := range strings.Split(string(res), "\n") {
if reg.MatchString(line) {
logs = append(logs, line)
}
}

return strings.Join(logs, "\n\r") + "\n\r", nil
}

// GetTerminal starts a new terminal session via the given WebSocket connection.
Expand Down
1 change: 0 additions & 1 deletion plugins/resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"@nivo/bar": "^0.73.1",
"@patternfly/react-core": "^4.128.2",
"@patternfly/react-icons": "^4.10.11",
"@patternfly/react-log-viewer": "^4.1.19",
"@patternfly/react-table": "^4.27.24",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
Expand Down
12 changes: 10 additions & 2 deletions plugins/resources/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,12 @@ func (router *Router) getLogs(w http.ResponseWriter, r *http.Request) {
namespace := r.URL.Query().Get("namespace")
name := r.URL.Query().Get("name")
container := r.URL.Query().Get("container")
regex := r.URL.Query().Get("regex")
since := r.URL.Query().Get("since")
tail := r.URL.Query().Get("tail")
previous := r.URL.Query().Get("previous")

log.WithFields(logrus.Fields{"cluster": clusterName, "namespace": namespace, "name": name, "container": container, "since": since, "previous": previous}).Tracef("getLogs")
log.WithFields(logrus.Fields{"cluster": clusterName, "namespace": namespace, "name": name, "container": container, "regex": regex, "since": since, "previous": previous}).Tracef("getLogs")

cluster := router.clusters.GetCluster(clusterName)
if cluster == nil {
Expand All @@ -298,13 +300,19 @@ func (router *Router) getLogs(w http.ResponseWriter, r *http.Request) {
return
}

parsedTail, err := strconv.ParseInt(tail, 10, 64)
if err != nil {
errresponse.Render(w, r, err, http.StatusBadRequest, "Could not parse tail parameter")
return
}

parsedPrevious, err := strconv.ParseBool(previous)
if err != nil {
errresponse.Render(w, r, err, http.StatusBadRequest, "Could not parse previous parameter")
return
}

logs, err := cluster.GetLogs(r.Context(), namespace, name, container, parsedSince, parsedPrevious)
logs, err := cluster.GetLogs(r.Context(), namespace, name, container, regex, parsedSince, parsedTail, parsedPrevious)
if err != nil {
errresponse.Render(w, r, err, http.StatusBadGateway, "Could not get logs")
return
Expand Down
18 changes: 18 additions & 0 deletions plugins/resources/src/components/panel/details/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Delete from './actions/Delete';
import Edit from './actions/Edit';
import { IAlert } from '../../../utils/interfaces';
import { IResource } from '@kobsio/plugin-core';
import Logs from './actions/Logs';
import Restart from './actions/Restart';
import Scale from './actions/Scale';
import Terminal from './actions/Terminal';
Expand All @@ -24,6 +25,7 @@ const Actions: React.FunctionComponent<IActionProps> = ({ request, resource, ref
const [showScale, setShowScale] = useState<boolean>(false);
const [showRestart, setShowRestart] = useState<boolean>(false);
const [showCreateJob, setShowCreateJob] = useState<boolean>(false);
const [showLogs, setShowLogs] = useState<boolean>(false);
const [showTerminal, setShowTerminal] = useState<boolean>(false);
const [showCreateEphemeralContainer, setShowCreateEphemeralContainer] = useState<boolean>(false);
const [showEdit, setShowEdit] = useState<boolean>(false);
Expand Down Expand Up @@ -82,6 +84,20 @@ const Actions: React.FunctionComponent<IActionProps> = ({ request, resource, ref
);
}

if (request.resource === 'pods') {
dropdownItems.push(
<DropdownItem
key="logs"
onClick={(): void => {
setShowDropdown(false);
setShowLogs(true);
}}
>
Logs
</DropdownItem>,
);
}

if (request.resource === 'pods') {
dropdownItems.push(
<DropdownItem
Expand Down Expand Up @@ -184,6 +200,8 @@ const Actions: React.FunctionComponent<IActionProps> = ({ request, resource, ref
refetch={refetch}
/>

<Logs request={request} resource={resource} show={showLogs} setShow={setShowLogs} />

<Terminal request={request} resource={resource} show={showTerminal} setShow={setShowTerminal} />

<CreateEphemeralContainer
Expand Down
14 changes: 0 additions & 14 deletions plugins/resources/src/components/panel/details/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import Actions from './Actions';
import Dashboards from './Dashboards';
import Events from './Events';
import Links from './Links';
import Logs from './Logs';
import Overview from './Overview';
import Pods from './Pods';

Expand Down Expand Up @@ -103,19 +102,6 @@ const Details: React.FunctionComponent<IDetailsProps> = ({ request, resource, cl
</div>
</Tab>

{request.resource === 'pods' ? (
<Tab eventKey="logs" title={<TabTitleText>Logs</TabTitleText>}>
<div style={{ maxWidth: '100%', overflowX: 'scroll', padding: '24px 24px' }}>
<Logs
cluster={resource.cluster.title}
namespace={resource.namespace ? resource.namespace.title : ''}
name={resource.name.title}
pod={resource.props}
/>
</div>
</Tab>
) : null}

{podSelector || request.resource === 'nodes' ? (
<Tab eventKey="pods" title={<TabTitleText>Pods</TabTitleText>}>
<div style={{ maxWidth: '100%', overflowX: 'scroll', padding: '24px 24px' }}>
Expand Down
106 changes: 0 additions & 106 deletions plugins/resources/src/components/panel/details/Logs.tsx

This file was deleted.

Loading