157 lines
4.3 KiB
Go
157 lines
4.3 KiB
Go
// Copyright 2023 Dolthub, Inc.
|
|
//
|
|
// 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.
|
|
|
|
package sqlserver
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
iofs "io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/dolthub/dolt/go/libraries/doltcore/dbfactory"
|
|
"github.com/dolthub/dolt/go/libraries/utils/filesys"
|
|
)
|
|
|
|
const ServerLocalCredsFile = "sql-server.info"
|
|
|
|
// LocalCreds is a struct that contains information about how to access the
|
|
// locally running server for a CLI process which wants to operate against a
|
|
// database while a sql-server process is running. It contains the pid of the
|
|
// process that created the lockfile, the port that the server is running on
|
|
// and the password to be used connecting to the server.
|
|
//
|
|
// Pid is a legacy field which is retained for compatibility but no longer
|
|
// influences the behavior of the running program(s).
|
|
type LocalCreds struct {
|
|
Pid int
|
|
Port int
|
|
Secret string
|
|
}
|
|
|
|
func NewLocalCreds(port int) *LocalCreds {
|
|
return &LocalCreds{os.Getpid(), port, uuid.New().String()}
|
|
}
|
|
|
|
// Best effort attempt to remove local creds file persisted as the Filesys
|
|
// rooted there.
|
|
func RemoveLocalCreds(fs filesys.Filesys) {
|
|
credsFilePath, err := fs.Abs(filepath.Join(dbfactory.DoltDir, ServerLocalCredsFile))
|
|
if err != nil {
|
|
return
|
|
}
|
|
_ = fs.Delete(credsFilePath, false)
|
|
}
|
|
|
|
// WriteLocalCreds writes a file containing the contents of LocalCreds to the
|
|
// DoltDir rooted at the provided Filesys.
|
|
func WriteLocalCreds(fs filesys.Filesys, creds *LocalCreds) error {
|
|
// if the DoltDir doesn't exist, create it.
|
|
doltDir, err := fs.Abs(dbfactory.DoltDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = fs.MkDirs(doltDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
credsFile, err := fs.Abs(filepath.Join(dbfactory.DoltDir, ServerLocalCredsFile))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
portStr := strconv.Itoa(creds.Port)
|
|
if creds.Port < 0 {
|
|
portStr = "-"
|
|
}
|
|
|
|
return fs.WriteFile(credsFile, []byte(fmt.Sprintf("%d:%s:%s", creds.Pid, portStr, creds.Secret)), 0600)
|
|
}
|
|
|
|
// Starting at `fs`, look for the a ServerLocalCredsFile in the .dolt directory
|
|
// of this directory and every parent directory, until we find one. When we
|
|
// find one, we return its contents if we can open and parse it successfully.
|
|
// Otherwise, we return an error associated with attempting to read it. If we
|
|
// do not find anything all the way up to the root of the filesystem, returns
|
|
// `nil` *LocalCreds and a `nil` error.
|
|
func FindAndLoadLocalCreds(fs filesys.Filesys) (creds *LocalCreds, err error) {
|
|
root, err := fs.Abs(".")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for root != "" && root[len(root)-1] != filepath.Separator {
|
|
creds, err := LoadLocalCreds(fs)
|
|
if err == nil {
|
|
return creds, err
|
|
}
|
|
// If we have an error that is not ErrNotExist, for example, a
|
|
// permission error opening the credentials file, or an error
|
|
// indicating that the contents of the file were malformed, go
|
|
// ahead and return the error and terminate our search here.
|
|
if !errors.Is(err, iofs.ErrNotExist) {
|
|
return nil, err
|
|
}
|
|
fs, err = fs.WithWorkingDir("..")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
root, err = fs.Abs(".")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func LoadLocalCreds(fs filesys.Filesys) (creds *LocalCreds, err error) {
|
|
rd, err := fs.OpenForRead(filepath.Join(dbfactory.DoltDir, ServerLocalCredsFile))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rd.Close()
|
|
|
|
b := make([]byte, 256)
|
|
n, err := rd.Read(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data := strings.TrimSpace(string(b[:n]))
|
|
|
|
parts := strings.Split(data, ":")
|
|
if len(parts) != 3 {
|
|
return nil, errors.New("invalid lock file format")
|
|
}
|
|
|
|
pid, err := strconv.Atoi(parts[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
port := -1
|
|
if parts[1] != "-" {
|
|
port, err = strconv.Atoi(parts[1])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
secret := parts[2]
|
|
return &LocalCreds{Pid: pid, Port: port, Secret: secret}, nil
|
|
}
|