• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dergeberl / kubeteach / 8354446339

20 Mar 2024 05:53AM UTC coverage: 88.483% (-1.0%) from 89.48%
8354446339

Pull #395

github

web-flow
Bump postcss from 8.4.35 to 8.4.37 in /dashboard

Bumps [postcss](https://github.com/postcss/postcss) from 8.4.35 to 8.4.37.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.35...8.4.37)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #395: Bump postcss from 8.4.35 to 8.4.37 in /dashboard

799 of 903 relevant lines covered (88.48%)

12.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.76
/pkg/dashboard/dashboard.go
1
/*
2
Copyright 2021 Maximilian Geberl.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
// Package dashboard for kubeteach
18
package dashboard
19

20
import (
21
        "context"
22
        "encoding/base64"
23
        "encoding/json"
24
        "fmt"
25
        "net/http"
26
        "net/http/httputil"
27
        "net/url"
28
        "os"
29
        "sort"
30
        "time"
31

32
        kubeteachv1alpha1 "github.com/dergeberl/kubeteach/api/v1alpha1"
33
        "sigs.k8s.io/controller-runtime/pkg/client"
34

35
        "github.com/go-chi/chi/v5"
36
        "github.com/go-chi/chi/v5/middleware"
37
)
38

39
// Environment variables
40
const (
41
        EnvWebterminalCredentials     = "WEBTERMINAL_CREDENTIALS"
42
        EnvDashboardBasicAuthUser     = "DASHBOARD_BASIC_AUTH_USER"
43
        EnvDashboardBasicAuthPassword = "DASHBOARD_BASIC_AUTH_PASSWORD"
44
)
45

46
// Config values for api
47
type Config struct {
48
        client                 client.Client
49
        listenAddr             string
50
        dashboardContent       string
51
        basicAuthUser          string
52
        basicAuthPassword      string
53
        webterminalEnable      bool
54
        webterminalHost        string
55
        webterminalPort        string
56
        webterminalCredentials string
57
}
58

59
type task struct {
60
        Name        string `json:"name"`
61
        Namespace   string `json:"namespace"`
62
        Title       string `json:"title"`
63
        Description string `json:"description"`
64
        UID         string `json:"uid"`
65
}
66

67
type tasks []task
68

69
func (a tasks) Len() int           { return len(a) }
2✔
70
func (a tasks) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
×
71
func (a tasks) Less(i, j int) bool { return a[i].Name < a[j].Name }
2✔
72

73
type taskStatus struct {
74
        Status string `json:"status"`
75
}
76

77
// New creates a new config for the api
78
func New(
79
        client client.Client,
80
        listenAddr string,
81
        dashboardContent string,
82
        basicAuthUser string,
83
        basicAuthPassword string,
84
        webterminalEnable bool,
85
        webterminalHost string,
86
        webterminalPort string,
87
        webterminalCredentials string,
88
) Config {
3✔
89
        if os.Getenv(EnvWebterminalCredentials) != "" {
3✔
90
                webterminalCredentials = os.Getenv(EnvWebterminalCredentials)
×
91
        }
×
92
        if os.Getenv(EnvDashboardBasicAuthUser) != "" {
3✔
93
                basicAuthUser = os.Getenv(EnvDashboardBasicAuthUser)
×
94
        }
×
95
        if os.Getenv(EnvDashboardBasicAuthPassword) != "" {
3✔
96
                basicAuthPassword = os.Getenv(EnvDashboardBasicAuthPassword)
×
97
        }
×
98
        return Config{
3✔
99
                client:                 client,
3✔
100
                listenAddr:             listenAddr,
3✔
101
                dashboardContent:       dashboardContent,
3✔
102
                basicAuthUser:          basicAuthUser,
3✔
103
                basicAuthPassword:      basicAuthPassword,
3✔
104
                webterminalEnable:      webterminalEnable,
3✔
105
                webterminalHost:        webterminalHost,
3✔
106
                webterminalPort:        webterminalPort,
3✔
107
                webterminalCredentials: webterminalCredentials,
3✔
108
        }
3✔
109
}
110

111
// Run api webserver
112
func (c *Config) Run() error {
3✔
113
        server := &http.Server{
3✔
114
                Addr:              c.listenAddr,
3✔
115
                ReadHeaderTimeout: 15 * time.Second, //nolint: gomnd // static timeout
3✔
116
                Handler:           c.configureChi(),
3✔
117
        }
3✔
118
        return server.ListenAndServe()
3✔
119
}
3✔
120

121
func (c *Config) configureChi() *chi.Mux {
3✔
122
        r := chi.NewRouter()
3✔
123
        if c.basicAuthUser != "" || c.basicAuthPassword != "" {
4✔
124
                r.Use(middleware.BasicAuth("", map[string]string{c.basicAuthUser: c.basicAuthPassword}))
1✔
125
        }
1✔
126
        r.Route("/", func(r chi.Router) {
6✔
127
                fs := http.FileServer(http.Dir(c.dashboardContent))
3✔
128
                r.Handle("/*", fs)
3✔
129

3✔
130
                r.Route("/api", func(r chi.Router) {
6✔
131
                        r.Route("/tasks", func(r chi.Router) {
6✔
132
                                r.Get("/", c.taskList)
3✔
133
                        })
3✔
134
                        r.Route("/taskstatus", func(r chi.Router) {
6✔
135
                                r.Get("/{uid}", c.taskStatus)
3✔
136
                        })
3✔
137
                })
138
                if c.webterminalEnable {
4✔
139
                        r.Route("/shell", func(r chi.Router) {
2✔
140
                                r.HandleFunc("/*", c.webterminalForward)
1✔
141
                        })
1✔
142
                }
143
        })
144
        return r
3✔
145
}
146

147
func (c *Config) taskList(w http.ResponseWriter, _ *http.Request) {
3✔
148
        if c.client == nil {
4✔
149
                http.Error(w, "Kubernetes client not functional", http.StatusInternalServerError)
1✔
150
                return
1✔
151
        }
1✔
152
        ctx := context.Background()
2✔
153
        taskList := &kubeteachv1alpha1.TaskDefinitionList{}
2✔
154
        err := c.client.List(ctx, taskList)
2✔
155
        if err != nil {
2✔
156
                http.Error(w, "Kubernetes client not functional", http.StatusInternalServerError)
×
157
                return
×
158
        }
×
159
        var tasksAPI tasks
2✔
160
        for _, t := range taskList.Items {
6✔
161
                tasksAPI = append(tasksAPI, task{
4✔
162
                        Namespace:   t.Namespace,
4✔
163
                        Name:        t.Name,
4✔
164
                        UID:         string(t.UID),
4✔
165
                        Title:       t.Spec.TaskSpec.Title,
4✔
166
                        Description: t.Spec.TaskSpec.Description,
4✔
167
                })
4✔
168
        }
4✔
169
        sort.Sort(tasksAPI)
2✔
170
        output, err := json.Marshal(tasksAPI)
2✔
171
        if err != nil {
2✔
172
                http.Error(w, "JSON could not be generated", http.StatusInternalServerError)
×
173
                return
×
174
        }
×
175
        _, _ = fmt.Fprint(w, string(output))
2✔
176
}
177

178
func (c *Config) taskStatus(w http.ResponseWriter, r *http.Request) {
3✔
179
        if c.client == nil {
4✔
180
                http.Error(w, "Kubernetes client not functional", http.StatusInternalServerError)
1✔
181
                return
1✔
182
        }
1✔
183
        ctx := context.Background()
2✔
184
        uid := chi.URLParam(r, "uid")
2✔
185
        taskList := &kubeteachv1alpha1.TaskDefinitionList{}
2✔
186
        err := c.client.List(ctx, taskList)
2✔
187
        if err != nil {
2✔
188
                http.Error(w, "Kubernetes client not functional", http.StatusInternalServerError)
×
189
                return
×
190
        }
×
191
        for _, t := range taskList.Items {
5✔
192
                if string(t.UID) == uid {
4✔
193
                        output, err := json.Marshal(taskStatus{Status: *t.Status.State})
1✔
194
                        if err != nil {
1✔
195
                                http.Error(w, "JSON could not be generated", http.StatusInternalServerError)
×
196
                                return
×
197
                        }
×
198
                        _, _ = fmt.Fprint(w, string(output))
1✔
199
                        return
1✔
200
                }
201
        }
202
        http.Error(w, "No task with uid found", http.StatusNotFound)
1✔
203
}
204

205
func (c *Config) webterminalForward(writer http.ResponseWriter, request *http.Request) {
1✔
206
        rev := httputil.ReverseProxy{Director: func(request *http.Request) {
2✔
207
                request.Header.Del("Authorization")
1✔
208
                shellHost, _ := url.Parse("http://" + c.webterminalHost + ":" + c.webterminalPort + "/")
1✔
209
                request.URL.Scheme = shellHost.Scheme
1✔
210
                request.URL.Host = shellHost.Host
1✔
211
                request.URL.RawQuery = shellHost.RawQuery + request.URL.RawQuery
1✔
212
                if c.webterminalCredentials != "" {
2✔
213
                        request.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(c.webterminalCredentials)))
1✔
214
                }
1✔
215
                request.Host = shellHost.Host
1✔
216
        }}
217
        rev.ServeHTTP(writer, request)
1✔
218
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc