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 lakefs instrumentation #6217

Merged
merged 21 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ docker run --pull always \
--name lakefs \
-p 8000:8000 \
treeverse/lakefs:latest \
run --local-settings
run --quickstart
```

Once you've got lakeFS running, open [http://127.0.0.1:8000/](http://127.0.0.1:8000/) in your web browser.
Expand Down
42 changes: 34 additions & 8 deletions cmd/lakefs/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/treeverse/lakefs/pkg/block"
"github.com/treeverse/lakefs/pkg/config"
"github.com/treeverse/lakefs/pkg/kv/local"
"github.com/treeverse/lakefs/pkg/logging"
"github.com/treeverse/lakefs/pkg/version"
)
Expand Down Expand Up @@ -41,26 +43,50 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.lakefs.yaml)")
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
rootCmd.PersistentFlags().Bool(config.UseLocalConfiguration, false, "Use lakeFS local default configuration")
rootCmd.PersistentFlags().Bool(config.QuickStartConfiguration, false, "Use lakeFS quickstart configuration")
}

func useLocal() bool {
res, err := rootCmd.PersistentFlags().GetBool(config.UseLocalConfiguration)
func validateQuickstartEnv(cfg *config.Config) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is a bit misleading as we verify the database and blockstore - but we override the configuration and not set them as default.
If we like to verify that the default as not override we should do the same as local - setup the right defaults for quick-start and verify after the configuration is loaded that the user didn't override the default for all the values we require.

if cfg.Database.Type != local.DriverName || cfg.Blockstore.Type != block.BlockstoreTypeLocal {
fmt.Printf("quickstart mode can only run with local settings\n")
os.Exit(1)
}
accessKey := "AKIAIOSFOLQUICKSTART"
secretKey := "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will need to lint ignore - gosec

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
accessKey := "AKIAIOSFOLQUICKSTART"
secretKey := "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
const (
accessKey = "AKIAIOSFOLQUICKSTART"
secretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
)

cfg.Installation.UserName = "quickstart"
cfg.Installation.AccessKeyID = config.SecureString(accessKey)
cfg.Installation.SecretAccessKey = config.SecureString(secretKey)
fmt.Printf("Access Key ID : %s \n", accessKey)
fmt.Printf("Secret Access Key: %s \n", secretKey)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmt.Printf("Access Key ID : %s \n", accessKey)
fmt.Printf("Secret Access Key: %s \n", secretKey)
fmt.Printf("Access Key ID : %s\n", accessKey)
fmt.Printf("Secret Access Key: %s\n", secretKey)

}

func useConfig(cfg string) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func useConfig(cfg string) bool {
func useConfig(flagName string) bool {

res, err := rootCmd.PersistentFlags().GetBool(cfg)
if err != nil {
fmt.Printf("%s: %s\n", config.UseLocalConfiguration, err)
fmt.Printf("%s: %s\n", cfg, err)
os.Exit(1)
}
if res {
printLocalWarning(os.Stderr, "local parameters configuration")
printLocalWarning(os.Stderr, fmt.Sprintf("%s parameters configuration", cfg))
}
return res
}

func newConfig() (*config.Config, error) {
if useLocal() {
return config.NewLocalConfig()
}
quickStart := useConfig(config.QuickStartConfiguration)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to verify that not both are on?

Copy link
Member Author

@N-o-Z N-o-Z Jul 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we wan't to enforce mutual exclusion - do you see an issue with it?


return config.NewConfig()
if useConfig(config.UseLocalConfiguration) || quickStart {
cfg, err := config.NewLocalConfig()
if err != nil {
return nil, err
}
if quickStart {
validateQuickstartEnv(cfg)
}
return cfg, err
} else {
return config.NewConfig()
}
}

func loadConfig() *config.Config {
Expand Down
2 changes: 1 addition & 1 deletion cmd/lakefs/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ func printWelcome(w io.Writer) {
const localWarningBanner = `
WARNING!

Using %s. This is suitable only for testing! It is NOT SUPPORTED for production.
Using %s. This is suitable only for testing! It is NOT SUPPORTED for production.
`

func printLocalWarning(w io.Writer, msg string) {
Expand Down
22 changes: 8 additions & 14 deletions docs/quickstart/launch.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,24 @@ Launch the lakeFS container:
docker run --name lakefs --pull always \
--rm --publish 8000:8000 \
treeverse/lakefs:latest \
run --local-settings
run --quickstart
```

After a few moments you should see the lakeFS container ready to use:
Quickstart mode includes initial setup and lakeFS is ready for use!
The lakeFS quickstart credentials are:

```
[…]
│ If you're running lakeFS locally for the first time,
│ complete the setup process at http://127.0.0.1:8000/setup
[…]

│ Access Key ID : "AKIAIOSFOLQUICKSTART"
│ Secret Access Key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
```

You're now ready to dive into lakeFS!

1. Open lakeFS's web interface at [http://127.0.0.1:8000/](http://127.0.0.1:8000/), enter your email address, and then click **Setup**.

2. Make a note of the Access Key ID and Secret Access Key and click on **Go To Login**.
1. Open lakeFS's web interface at [http://127.0.0.1:8000/](http://127.0.0.1:8000/), enter your email address, and then click **Go to Login**.

3. Login with the credentials that you've just created.
2. Login with the quickstart credentials.

4. You'll notice that there aren't any repositories created yet. Click the **Create Sample Repository** button.
3. You'll notice that there aren't any repositories created yet. Click the **Create Sample Repository** button.

<img width="75%" src="/assets/img/quickstart/empty-repo-list.png" alt="Empty lakeFS Repository list" class="quickstart"/>

Expand Down
38 changes: 38 additions & 0 deletions pkg/auth/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"context"
"encoding/base64"
"errors"
"os"
"runtime"
"strconv"
"strings"
"time"

"github.com/google/uuid"
Expand All @@ -20,6 +22,10 @@ const (
EmailKeyName = "encoded_user_email"
FeatureUpdatesKeyName = "feature_updates"
SecurityUpdatesKeyName = "security_updates"

InstrumentationSamplesRepo = "SamplesRepo"
InstrumentationQuickstart = "Quickstart"
InstrumentationRun = "Run"
)

type SetupStateName string
Expand Down Expand Up @@ -206,13 +212,45 @@ func (m *KVMetadataManager) IsInitialized(ctx context.Context) (bool, error) {
return !setupTimestamp.IsZero(), nil
}

// DockeEnvExists For testing purposes
var DockeEnvExists = "/.dockerenv"

func inK8sMetadata() string {
_, k8s := os.LookupEnv("KUBERNETES_SERVICE_HOST")
return strconv.FormatBool(k8s)
}

func inDockerMetadata() string {
var err error
if DockeEnvExists != "" {
_, err = os.Stat(DockeEnvExists)
}
return strconv.FormatBool(err == nil)
}

func getInstrumentationMetadata() string {
lakefsAccessKeyID := os.Getenv("LAKEFS_ACCESS_KEY_ID")
switch {
case strings.HasSuffix(lakefsAccessKeyID, "LKFSSAMPLES"):
return InstrumentationSamplesRepo
case strings.HasSuffix(lakefsAccessKeyID, "QUICKSTART"):
return InstrumentationQuickstart
default:
return InstrumentationRun
}
}

func (m *KVMetadataManager) GetMetadata(ctx context.Context) (map[string]string, error) {
metadata := make(map[string]string)
metadata["lakefs_version"] = m.version
metadata["lakefs_kv_type"] = m.kvType
metadata["golang_version"] = runtime.Version()
metadata["architecture"] = runtime.GOARCH
metadata["os"] = runtime.GOOS
metadata["is_k8s"] = inK8sMetadata()
metadata["is_docker"] = inDockerMetadata()
metadata["instrumentation"] = getInstrumentationMetadata()

err := m.writeMetadata(ctx, metadata)
if err != nil {
return nil, err
Expand Down
53 changes: 53 additions & 0 deletions pkg/auth/metadata_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package auth_test

import (
"context"
"os"
"strconv"
"testing"
"time"

"github.com/stretchr/testify/require"
"github.com/treeverse/lakefs/pkg/auth"
"github.com/treeverse/lakefs/pkg/auth/model"
"github.com/treeverse/lakefs/pkg/kv/kvtest"
)

func validateInstrumentation(t *testing.T, ctx context.Context, mgr *auth.KVMetadataManager, inst string, k8s, docker bool) {
md, err := mgr.GetMetadata(ctx)
require.NoError(t, err)
require.Equal(t, inst, md["instrumentation"])
require.Equal(t, strconv.FormatBool(k8s), md["is_k8s"])
require.Equal(t, strconv.FormatBool(docker), md["is_docker"])
}

func TestInstrumentation(t *testing.T) {
ctx := context.Background()
kvStore := kvtest.GetStore(ctx, t)

_ = kvStore.Set(ctx, []byte(model.PartitionKey), []byte(model.MetadataKeyPath(auth.SetupTimestampKeyName)), []byte(time.Now().Format(time.RFC3339)))
mgr := auth.NewKVMetadataManager("test", "12345", "mem", kvStore)

// No env vars - defaults to run
validateInstrumentation(t, ctx, mgr, auth.InstrumentationRun, false, false)

// Add quickstart env var with wrong value
require.NoError(t, os.Setenv("QUICKSTART", "fff"))
validateInstrumentation(t, ctx, mgr, auth.InstrumentationRun, false, false)

// Add docker env file
auth.DockeEnvExists = ""
validateInstrumentation(t, ctx, mgr, auth.InstrumentationRun, false, true)

// Add sample repo env var
require.NoError(t, os.Setenv("LAKEFS_ACCESS_KEY_ID", "LKFSSAMPLES"))
validateInstrumentation(t, ctx, mgr, auth.InstrumentationSamplesRepo, false, true)

// Add quickstart env var with right value
require.NoError(t, os.Setenv("LAKEFS_ACCESS_KEY_ID", "QUICKSTART"))
validateInstrumentation(t, ctx, mgr, auth.InstrumentationQuickstart, false, true)

// Add K8s env var
require.NoError(t, os.Setenv("KUBERNETES_SERVICE_HOST", ""))
validateInstrumentation(t, ctx, mgr, auth.InstrumentationQuickstart, true, true)
}
5 changes: 4 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ var (

// UseLocalConfiguration set to true will add defaults that enable a lakeFS run
// without any other configuration like DB or blockstore.
const UseLocalConfiguration = "local-settings"
const (
UseLocalConfiguration = "local-settings"
QuickStartConfiguration = "quickstart"
)

type OIDC struct {
// configure how users are handled on the lakeFS side:
Expand Down
2 changes: 1 addition & 1 deletion pkg/samplerepo/assets/sample/README.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ Alternatively you might want to have a look at [lakeFS Cloud](https://lakefs.clo

## lakeFS Samples

The [lakeFS Samples](https://github.com/treeverse/lakeFS-samples) GitHub repository includes some excellent examples including.
The [lakeFS Samples](https://github.com/treeverse/lakeFS-samples) GitHub repository includes some excellent examples including:

* How to implement multi-table transaction on multiple Delta Tables
* Notebooks to show integration of lakeFS with Spark, Python, Delta Lake, Airflow and Hooks.
Expand Down