Skip to content
This repository was archived by the owner on Apr 27, 2024. It is now read-only.

Commit 506a12b

Browse files
authored
Merge pull request #3 from kubectyl:patch-2
Updates
2 parents 18593e1 + 9bde87c commit 506a12b

26 files changed

+756
-582
lines changed

cmd/diagnostics.go

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package cmd
22

33
import (
4+
"bytes"
45
"errors"
56
"fmt"
67
"io"
8+
"math/rand"
9+
"mime/multipart"
710
"net/http"
811
"net/url"
9-
"os"
1012
"os/exec"
1113
"path"
1214
"strconv"
@@ -28,15 +30,15 @@ import (
2830
)
2931

3032
const (
31-
DefaultHastebinUrl = "https://ptero.co"
33+
DefaultPastebinUrl = "https://pb.kubectyl.org"
3234
DefaultLogLines = 200
3335
)
3436

3537
var diagnosticsArgs struct {
3638
IncludeEndpoints bool
3739
IncludeLogs bool
3840
ReviewBeforeUpload bool
39-
HastebinURL string
41+
PastebinURL string
4042
LogLines int
4143
}
4244

@@ -51,7 +53,7 @@ func newDiagnosticsCommand() *cobra.Command {
5153
Run: diagnosticsCmdRun,
5254
}
5355

54-
command.Flags().StringVar(&diagnosticsArgs.HastebinURL, "hastebin-url", DefaultHastebinUrl, "the url of the hastebin instance to use")
56+
command.Flags().StringVar(&diagnosticsArgs.PastebinURL, "hastebin-url", DefaultPastebinUrl, "the url of the hastebin instance to use")
5557
command.Flags().IntVar(&diagnosticsArgs.LogLines, "log-lines", DefaultLogLines, "the number of log lines to include in the report")
5658

5759
return command
@@ -77,7 +79,7 @@ func diagnosticsCmdRun(*cobra.Command, []string) {
7779
{
7880
Name: "ReviewBeforeUpload",
7981
Prompt: &survey.Confirm{
80-
Message: "Do you want to review the collected data before uploading to " + diagnosticsArgs.HastebinURL + "?",
82+
Message: "Do you want to review the collected data before uploading to " + diagnosticsArgs.PastebinURL + "?",
8183
Help: "The data, especially the logs, might contain sensitive information, so you should review it. You will be asked again if you want to upload.",
8284
Default: true,
8385
},
@@ -112,27 +114,17 @@ func diagnosticsCmdRun(*cobra.Command, []string) {
112114
{"Logs Directory", cfg.System.LogDirectory},
113115
{"Data Directory", cfg.System.Data},
114116
{"Archive Directory", cfg.System.ArchiveDirectory},
115-
{"Backup Directory", cfg.System.BackupDirectory},
116117

117-
{"Username", cfg.System.Username},
118118
{"Server Time", time.Now().Format(time.RFC1123Z)},
119119
{"Debug Mode", fmt.Sprintf("%t", cfg.Debug)},
120120
}
121121

122-
table := tablewriter.NewWriter(os.Stdout)
122+
table := tablewriter.NewWriter(output)
123123
table.SetHeader([]string{"Variable", "Value"})
124124
table.SetRowLine(true)
125125
table.AppendBulk(data)
126126
table.Render()
127127

128-
printHeader(output, "Docker: Running Containers")
129-
c := exec.Command("docker", "ps")
130-
if co, err := c.Output(); err == nil {
131-
output.Write(co)
132-
} else {
133-
fmt.Fprint(output, "Couldn't list containers: ", err)
134-
}
135-
136128
printHeader(output, "Latest Kuber Logs")
137129
if diagnosticsArgs.IncludeLogs {
138130
p := "/var/log/kubectyl/kuber.log"
@@ -162,16 +154,38 @@ func diagnosticsCmdRun(*cobra.Command, []string) {
162154
fmt.Println(output.String())
163155
fmt.Print("--------------- end of report ---------------\n\n")
164156

165-
// upload := !diagnosticsArgs.ReviewBeforeUpload
166-
// if !upload {
167-
// survey.AskOne(&survey.Confirm{Message: "Upload to " + diagnosticsArgs.HastebinURL + "?", Default: false}, &upload)
168-
// }
169-
// if upload {
170-
// u, err := uploadToHastebin(diagnosticsArgs.HastebinURL, output.String())
171-
// if err == nil {
172-
// fmt.Println("Your report is available here: ", u)
173-
// }
174-
// }
157+
upload := !diagnosticsArgs.ReviewBeforeUpload
158+
if !upload {
159+
survey.AskOne(&survey.Confirm{Message: "Upload to " + diagnosticsArgs.PastebinURL + "?", Default: false}, &upload)
160+
}
161+
if upload {
162+
passwordFunc := func(length int) string {
163+
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
164+
password := make([]byte, length)
165+
166+
for i := 0; i < length; i++ {
167+
password[i] = charset[rand.Intn(len(charset))]
168+
}
169+
170+
return string(password)
171+
}
172+
rand.Seed(time.Now().UnixNano())
173+
174+
password := passwordFunc(8)
175+
result, err := uploadToPastebin(diagnosticsArgs.PastebinURL, output.String(), password)
176+
if err == nil {
177+
seconds, err := strconv.Atoi(fmt.Sprintf("%v", result["expire"]))
178+
if err != nil {
179+
return
180+
}
181+
182+
expireTime := fmt.Sprintf("%d hours, %d minutes, %d seconds", seconds/3600, (seconds%3600)/60, seconds%60)
183+
184+
fmt.Println("Your report is available here:", result["url"])
185+
fmt.Println("Will expire in", expireTime)
186+
fmt.Printf("You can edit your pastebin here: %s\n", result["admin"])
187+
}
188+
}
175189
}
176190

177191
// func getDockerInfo() (types.Version, types.Info, error) {
@@ -190,31 +204,45 @@ func diagnosticsCmdRun(*cobra.Command, []string) {
190204
// return dockerVersion, dockerInfo, nil
191205
// }
192206

193-
func uploadToHastebin(hbUrl, content string) (string, error) {
194-
r := strings.NewReader(content)
195-
u, err := url.Parse(hbUrl)
207+
func uploadToPastebin(pbURL, content, password string) (map[string]interface{}, error) {
208+
payload := &bytes.Buffer{}
209+
writer := multipart.NewWriter(payload)
210+
writer.WriteField("c", content)
211+
writer.WriteField("e", "300")
212+
writer.WriteField("s", password)
213+
writer.Close()
214+
215+
u, err := url.Parse(pbURL)
196216
if err != nil {
197-
return "", err
217+
return nil, err
198218
}
199-
u.Path = path.Join(u.Path, "documents")
200-
res, err := http.Post(u.String(), "plain/text", r)
219+
220+
req, err := http.NewRequest("POST", u.String(), payload)
221+
if err != nil {
222+
return nil, err
223+
}
224+
req.Header.Set("Content-Type", writer.FormDataContentType())
225+
226+
client := &http.Client{}
227+
res, err := client.Do(req)
201228
if err != nil || res.StatusCode != 200 {
202-
fmt.Println("Failed to upload report to ", u.String(), err)
203-
return "", err
229+
fmt.Println("Failed to upload report to", u.String(), err)
230+
return nil, err
204231
}
232+
205233
pres := make(map[string]interface{})
206234
body, err := io.ReadAll(res.Body)
207235
if err != nil {
208236
fmt.Println("Failed to parse response.", err)
209-
return "", err
237+
return nil, err
210238
}
211239
json.Unmarshal(body, &pres)
212-
if key, ok := pres["key"].(string); ok {
213-
u, _ := url.Parse(hbUrl)
214-
u.Path = path.Join(u.Path, key)
215-
return u.String(), nil
240+
if key, ok := pres["url"].(string); ok {
241+
u.Path = key
242+
return pres, nil
216243
}
217-
return "", errors.New("failed to find key in response")
244+
245+
return nil, errors.New("failed to find key in response")
218246
}
219247

220248
func redact(s string) string {

cmd/root.go

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,6 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
116116
if err := environment.CreateSftpSecret(); err != nil {
117117
log.WithField("error", err).Fatal("failed to create sftp secret")
118118
}
119-
if err := config.EnsureKubectylUser(); err != nil {
120-
log.WithField("error", err).Fatal("failed to create kubectyl system user")
121-
}
122-
log.WithFields(log.Fields{
123-
"username": config.Get().System.Username,
124-
"uid": config.Get().System.User.Uid,
125-
"gid": config.Get().System.User.Gid,
126-
}).Info("configured system user successfully")
127119
if err := config.EnableLogRotation(); err != nil {
128120
log.WithField("error", err).Fatal("failed to configure log rotation on the system")
129121
return
@@ -256,7 +248,10 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
256248

257249
// we use goroutine to avoid blocking whole process
258250
go func() {
259-
if err := s.Environment.CreateSFTP(s.Context()); err != nil {
251+
ctx, cancel := context.WithCancel(context.Background())
252+
defer cancel()
253+
254+
if err := s.Environment.CreateSFTP(ctx, cancel); err != nil {
260255
log.WithField("error", err).Warn("failed to create server SFTP pod")
261256
}
262257
}()
@@ -303,11 +298,6 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
303298
log.WithField("error", err).Error("failed to create archive directory")
304299
}
305300

306-
// Ensure the backup directory exists.
307-
if err := os.MkdirAll(sys.BackupDirectory, 0o755); err != nil {
308-
log.WithField("error", err).Error("failed to create backup directory")
309-
}
310-
311301
autotls, _ := cmd.Flags().GetBool("auto-tls")
312302
tlshostname, _ := cmd.Flags().GetString("tls-hostname")
313303
if autotls && tlshostname == "" {

config/config.go

Lines changed: 1 addition & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ import (
66
"fmt"
77
"os"
88
"os/exec"
9-
"os/user"
109
"path"
1110
"path/filepath"
1211
"regexp"
13-
"strings"
1412
"sync"
1513
"text/template"
1614
"time"
@@ -21,8 +19,6 @@ import (
2119
"github.com/creasty/defaults"
2220
"github.com/gbrlsnchs/jwt/v3"
2321
"gopkg.in/yaml.v2"
24-
25-
"github.com/kubectyl/kuber/system"
2622
)
2723

2824
const DefaultLocation = "/etc/kubectyl/config.yml"
@@ -134,44 +130,17 @@ type SystemConfiguration struct {
134130
// Directory where server archives for transferring will be stored.
135131
ArchiveDirectory string `default:"/var/lib/kubectyl/archives" yaml:"archive_directory"`
136132

137-
// Directory where local backups will be stored on the machine.
138-
BackupDirectory string `default:"/var/lib/kubectyl/backups" yaml:"backup_directory"`
139-
140133
// TmpDirectory specifies where temporary files for Kubectyl installation processes
141134
// should be created. This supports environments running docker-in-docker.
142135
TmpDirectory string `default:"/tmp/kubectyl" yaml:"tmp_directory"`
143136

144-
// The user that should own all of the server files, and be used for containers.
145-
Username string `default:"kubectyl" yaml:"username"`
146-
147137
// The timezone for this Kuber instance. This is detected by Kuber automatically if possible,
148138
// and falls back to UTC if not able to be detected. If you need to set this manually, that
149139
// can also be done.
150140
//
151141
// This timezone value is passed into all containers created by Kuber.
152142
Timezone string `yaml:"timezone"`
153143

154-
// Definitions for the user that gets created to ensure that we can quickly access
155-
// this information without constantly having to do a system lookup.
156-
User struct {
157-
// Rootless controls settings related to rootless container daemons.
158-
Rootless struct {
159-
// Enabled controls whether rootless containers are enabled.
160-
Enabled bool `yaml:"enabled" default:"false"`
161-
// ContainerUID controls the UID of the user inside the container.
162-
// This should likely be set to 0 so the container runs as the user
163-
// running Kuber.
164-
ContainerUID int `yaml:"container_uid" default:"0"`
165-
// ContainerGID controls the GID of the user inside the container.
166-
// This should likely be set to 0 so the container runs as the user
167-
// running Kuber.
168-
ContainerGID int `yaml:"container_gid" default:"0"`
169-
} `yaml:"rootless"`
170-
171-
Uid int `yaml:"uid"`
172-
Gid int `yaml:"gid"`
173-
} `yaml:"user"`
174-
175144
// The amount of time in seconds that can elapse before a server's disk space calculation is
176145
// considered stale and a re-check should occur. DANGER: setting this value too low can seriously
177146
// impact system performance and cause massive I/O bottlenecks and high CPU usage for the Kuber
@@ -202,7 +171,7 @@ type SystemConfiguration struct {
202171
EnableLogRotate bool `default:"true" yaml:"enable_log_rotate"`
203172

204173
// The number of lines to send when a server connects to the websocket.
205-
WebsocketLogCount int `default:"150" yaml:"websocket_log_count"`
174+
WebsocketLogCount int64 `default:"150" yaml:"websocket_log_count"`
206175

207176
Sftp SftpConfiguration `yaml:"sftp"`
208177

@@ -422,78 +391,6 @@ func WriteToDisk(c *Configuration) error {
422391
return nil
423392
}
424393

425-
// EnsureKubectylUser ensures that the Kubectyl core user exists on the
426-
// system. This user will be the owner of all data in the root data directory
427-
// and is used as the user within containers. If files are not owned by this
428-
// user there will be issues with permissions on Docker mount points.
429-
//
430-
// This function IS NOT thread safe and should only be called in the main thread
431-
// when the application is booting.
432-
func EnsureKubectylUser() error {
433-
sysName, err := getSystemName()
434-
if err != nil {
435-
return err
436-
}
437-
438-
// Our way of detecting if kuber is running inside of Docker.
439-
if sysName == "distroless" {
440-
_config.System.Username = system.FirstNotEmpty(os.Getenv("KUBER_USERNAME"), "kubectyl")
441-
_config.System.User.Uid = system.MustInt(system.FirstNotEmpty(os.Getenv("KUBER_UID"), "988"))
442-
_config.System.User.Gid = system.MustInt(system.FirstNotEmpty(os.Getenv("KUBER_GID"), "988"))
443-
return nil
444-
}
445-
446-
if _config.System.User.Rootless.Enabled {
447-
log.Info("rootless mode is enabled, skipping user creation...")
448-
u, err := user.Current()
449-
if err != nil {
450-
return err
451-
}
452-
_config.System.Username = u.Username
453-
_config.System.User.Uid = system.MustInt(u.Uid)
454-
_config.System.User.Gid = system.MustInt(u.Gid)
455-
return nil
456-
}
457-
458-
log.WithField("username", _config.System.Username).Info("checking for kubectyl system user")
459-
u, err := user.Lookup(_config.System.Username)
460-
// If an error is returned but it isn't the unknown user error just abort
461-
// the process entirely. If we did find a user, return it immediately.
462-
if err != nil {
463-
if _, ok := err.(user.UnknownUserError); !ok {
464-
return err
465-
}
466-
} else {
467-
_config.System.User.Uid = system.MustInt(u.Uid)
468-
_config.System.User.Gid = system.MustInt(u.Gid)
469-
return nil
470-
}
471-
472-
command := fmt.Sprintf("useradd --system --no-create-home --shell /usr/sbin/nologin %s", _config.System.Username)
473-
// Alpine Linux is the only OS we currently support that doesn't work with the useradd
474-
// command, so in those cases we just modify the command a bit to work as expected.
475-
if strings.HasPrefix(sysName, "alpine") {
476-
command = fmt.Sprintf("adduser -S -D -H -G %[1]s -s /sbin/nologin %[1]s", _config.System.Username)
477-
// We have to create the group first on Alpine, so do that here before continuing on
478-
// to the user creation process.
479-
if _, err := exec.Command("addgroup", "-S", _config.System.Username).Output(); err != nil {
480-
return err
481-
}
482-
}
483-
484-
split := strings.Split(command, " ")
485-
if _, err := exec.Command(split[0], split[1:]...).Output(); err != nil {
486-
return err
487-
}
488-
u, err = user.Lookup(_config.System.Username)
489-
if err != nil {
490-
return err
491-
}
492-
_config.System.User.Uid = system.MustInt(u.Uid)
493-
_config.System.User.Gid = system.MustInt(u.Gid)
494-
return nil
495-
}
496-
497394
// FromFile reads the configuration from the provided file and stores it in the
498395
// global singleton for this instance.
499396
func FromFile(path string) error {
@@ -553,11 +450,6 @@ func ConfigureDirectories() error {
553450
return err
554451
}
555452

556-
log.WithField("path", _config.System.BackupDirectory).Debug("ensuring backup data directory exists")
557-
if err := os.MkdirAll(_config.System.BackupDirectory, 0o700); err != nil {
558-
return err
559-
}
560-
561453
return nil
562454
}
563455

0 commit comments

Comments
 (0)