jusrhee 5 gadi atpakaļ
vecāks
revīzija
c73aedc109

+ 10 - 7
README.md

@@ -7,14 +7,14 @@ Porter is a **dashboard for Helm** with support for the following features:
 
 **What's next for Porter?** View our [roadmap](https://github.com/porter-dev/porter/projects/1), or read our [mission statement](#mission-statement). 
 
-## Getting Started
-
-### Local Setup
+## Quick Start
 
 To view the dashboard locally, download our CLI and grab the latest release via:
 
 ```sh
-TBD
+curl "https://api.github.com/repos/porter-dev/porter/releases/latest"
+chmod +x ./porter
+sudo mv ./porter /usr/local/bin/porter
 ```
 
 Then run the dashboard (Docker engine must be running on the host machine):
@@ -23,11 +23,14 @@ Then run the dashboard (Docker engine must be running on the host machine):
 porter start
 ```
 
-### In-Cluster Setup
+When prompted, enter the admin email/password you would like to use. After the server has started, go to `localhost:8080` and **log in with the credentials you just set**. 
 
-TBD
+## Differences from Kubeapps
 
-## Alternative Tools
+As a disclaimer, we're big fans of [Kubeapps](https://github.com/kubeapps/kubeapps), and many of the initial features that we build out will be very similar. Currently, Porter's graph-based chart visualization is the only fundamental difference, and it should be assumed that most Kubeapps features will be supported on Porter in the near future. However, on the feature side, Porter will eventually support:
+- IDE-like tooling for chart creation, templating, and packaging
+- Deep integration with GitOps workflows and CI/CD tools
+- Visualization of lifecycle hooks and robust error tracing for deployments
 
 ## Mission Statement
 

+ 24 - 0
cli/cmd/docker/agent.go

@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"io"
 	"strings"
+	"time"
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/container"
@@ -184,6 +185,29 @@ func (a *Agent) WaitForContainerStop(id string) error {
 	return nil
 }
 
+// WaitForContainerHealthy waits until a container is returning a healthy status. Streak
+// is the maximum number of failures in a row, while timeout is the length of time between
+// checks.
+func (a *Agent) WaitForContainerHealthy(id string, streak int) error {
+	for {
+		cont, err := a.client.ContainerInspect(a.ctx, id)
+
+		if err != nil {
+			return a.handleDockerClientErr(err, "Error waiting for stopped container")
+		}
+
+		health := cont.State.Health
+
+		if health == nil || health.Status == "healthy" || health.FailingStreak >= streak {
+			break
+		}
+
+		time.Sleep(time.Second)
+	}
+
+	return nil
+}
+
 // ------------------------- AGENT HELPER FUNCTIONS ------------------------- //
 
 func (a *Agent) handleDockerClientErr(err error, errPrefix string) error {

+ 6 - 0
cli/cmd/docker/porter.go

@@ -199,6 +199,12 @@ func (a *Agent) pullAndCreatePostgresContainer(opts PostgresOpts) (id string, er
 		ExposedPorts: nat.PortSet{
 			"5432": struct{}{},
 		},
+		Healthcheck: &container.HealthConfig{
+			Test:     []string{"CMD-SHELL", "pg_isready"},
+			Interval: 10 * time.Second,
+			Timeout:  5 * time.Second,
+			Retries:  3,
+		},
 	}, &container.HostConfig{
 		Mounts: opts.Mounts,
 	}, nil, opts.Name)

+ 29 - 0
cli/cmd/start.go

@@ -3,7 +3,10 @@ package cmd
 import (
 	"fmt"
 	"os"
+	"os/exec"
 	"path/filepath"
+	"runtime"
+	"time"
 
 	"github.com/porter-dev/porter/cli/cmd/docker"
 	"k8s.io/client-go/util/homedir"
@@ -136,6 +139,8 @@ func start(
 
 	// if not insecure, or username/pw set incorrectly, prompt for new username/pw
 	if username, pw, err = credstore.Get(); !insecure && err != nil {
+		fmt.Println("Please register your admin account with an email and password:")
+
 		username, err = promptPlaintext("Email: ")
 
 		if err != nil {
@@ -265,6 +270,9 @@ func start(
 
 		pgID, err := agent.StartPostgresContainer(startOpts)
 
+		fmt.Println("Waiting for postgres:latest to be healthy...")
+		agent.WaitForContainerHealthy(pgID, 10)
+
 		if err != nil {
 			return err
 		}
@@ -300,9 +308,30 @@ func start(
 		return err
 	}
 
+	fmt.Println("Spinning up the server...")
+	time.Sleep(7 * time.Second)
+	openBrowser(fmt.Sprintf("http://localhost:%d/login?email=%s", port, username))
 	fmt.Printf("Server ready: listening on localhost:%d\n", port)
 
 	agent.WaitForContainerStop(id)
 
 	return nil
 }
+
+// openBrowser opens the specified URL in the default browser of the user.
+func openBrowser(url string) error {
+	var cmd string
+	var args []string
+
+	switch runtime.GOOS {
+	case "windows":
+		cmd = "cmd"
+		args = []string{"/c", "start"}
+	case "darwin":
+		cmd = "open"
+	default: // "linux", "freebsd", "openbsd", "netbsd"
+		cmd = "xdg-open"
+	}
+	args = append(args, url)
+	return exec.Command(cmd, args...).Start()
+}

+ 3 - 0
dashboard/src/main/Login.tsx

@@ -30,6 +30,9 @@ export default class Login extends Component<PropsType, StateType> {
   }
 
   componentDidMount() {
+    let urlParams = new URLSearchParams(window.location.search);
+    let emailFromCLI = urlParams.get('email');
+    emailFromCLI ? this.setState({email: emailFromCLI}) :
     document.addEventListener("keydown", this.handleKeyDown);
   }
 

+ 6 - 1
dashboard/src/main/home/dashboard/expanded-chart/ExpandedChart.tsx

@@ -48,7 +48,7 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
       namespace: currentChart.namespace,
       context: currentCluster,
       storage: StorageType.Secret
-    }, { name: currentChart.name, revision: 0 }, (err: any, res: any) => {
+    }, { name: currentChart.name, revision: currentChart.version }, (err: any, res: any) => {
       if (err) {
         console.log(err)
       } else {
@@ -102,9 +102,14 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
   }
 
   renderTabContents = () => {
+<<<<<<< HEAD
     let { currentChart, refreshChart, setSidebar } = this.props;
     let chart = this.state.revisionPreview || currentChart;
     
+=======
+    let { currentChart, refreshChart, setSidebar} = this.props;
+
+>>>>>>> 21e0edcb20b33dbb6af1eaa3649803a275019bdf
     if (this.state.currentTab === 'graph') {
       return (
         <GraphSection