Browse Source

Merge branch 'master' of https://github.com/porter-dev/porter into capi-preflight-checks

Justin Rhee 3 years ago
parent
commit
daa2d4876a

+ 6 - 2
Tiltfile

@@ -12,10 +12,14 @@ if config.tilt_subcommand == "down":
     local(command="rm -rf vendor")
     local(command="rm -rf dashboard/node_modules")
 
+build_args = "GOOS=linux GOARCH=arm64"
+if os.getenv("PLATFORM") == "amd64":
+    build_args = "GOOS=linux GOARCH=amd64"
+
 ## Build binary locally for faster devexp
 local_resource(
   name='porter-binary',
-  cmd='''GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -mod vendor -gcflags '-N -l' -tags ee -o ./bin/porter ./cmd/app/main.go''',
+  cmd='''GOWORK=off CGO_ENABLED=0 %s go build -mod vendor -gcflags '-N -l' -tags ee -o ./bin/porter ./cmd/app/main.go''' % build_args,
   deps=[
     "api",
     "build",
@@ -62,7 +66,7 @@ local_resource(
 # Migrations
 local_resource(
     name="migrations-binary",
-    cmd='''GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -mod vendor -gcflags '-N -l' -tags ee -o ./bin/migrate ./cmd/migrate/main.go ./cmd/migrate/migrate_ee.go''',
+    cmd='''GOWORK=off CGO_ENABLED=0 %s go build -mod vendor -gcflags '-N -l' -tags ee -o ./bin/migrate ./cmd/migrate/main.go ./cmd/migrate/migrate_ee.go''' % build_args,
     resource_deps=["postgresql"],
     labels=["porter"],
 )

+ 36 - 16
api/server/handlers/user/create_test.go

@@ -1,7 +1,6 @@
 package user_test
 
 import (
-	"fmt"
 	"net/http"
 	"testing"
 
@@ -18,8 +17,11 @@ func TestCreateUserSuccessful(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/users",
 		&types.CreateUserRequest{
-			Email:    "test@test.it",
-			Password: "somepassword",
+			FirstName:   "Mister",
+			LastName:    "Porter",
+			CompanyName: "Porter Technologies, Inc.",
+			Email:       "mrp@porter.run",
+			Password:    "somepassword",
 		},
 	)
 
@@ -35,7 +37,10 @@ func TestCreateUserSuccessful(t *testing.T) {
 
 	expUser := &types.CreateUserResponse{
 		ID:            1,
-		Email:         "test@test.it",
+		FirstName:     "Mister",
+		LastName:      "Porter",
+		CompanyName:   "Porter Technologies, Inc.",
+		Email:         "mrp@porter.run",
 		EmailVerified: false,
 	}
 
@@ -50,8 +55,11 @@ func TestCreateUserBadEmail(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/users",
 		&types.CreateUserRequest{
-			Email:    "notanemail",
-			Password: "somepassword",
+			FirstName:   "Mister",
+			LastName:    "Porter",
+			CompanyName: "Porter Technologies, Inc.",
+			Email:       "notanemail",
+			Password:    "somepassword",
 		},
 	)
 
@@ -66,7 +74,7 @@ func TestCreateUserBadEmail(t *testing.T) {
 	handler.ServeHTTP(rr, req)
 
 	apitest.AssertResponseError(t, rr, http.StatusBadRequest, &types.ExternalError{
-		Error: fmt.Sprintf("validation failed on field 'Email' on condition 'email'"),
+		Error: "validation failed on field 'Email' on condition 'email'",
 	})
 }
 
@@ -76,7 +84,10 @@ func TestCreateUserMissingField(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/users",
 		&types.CreateUserRequest{
-			Email: "test@test.it",
+			FirstName:   "Mister",
+			LastName:    "Porter",
+			CompanyName: "Porter Technologies, Inc.",
+			Email:       "mrp@porter.run",
 		},
 	)
 
@@ -91,7 +102,7 @@ func TestCreateUserMissingField(t *testing.T) {
 	handler.ServeHTTP(rr, req)
 
 	apitest.AssertResponseError(t, rr, http.StatusBadRequest, &types.ExternalError{
-		Error: fmt.Sprintf("validation failed on field 'Password' on condition 'required'"),
+		Error: "validation failed on field 'Password' on condition 'required'",
 	})
 }
 
@@ -101,8 +112,11 @@ func TestCreateUserSameEmail(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/users",
 		&types.CreateUserRequest{
-			Email:    "test@test.it",
-			Password: "somepassword",
+			FirstName:   "Mister",
+			LastName:    "Porter",
+			CompanyName: "Porter Technologies, Inc.",
+			Email:       "mrp@porter.run",
+			Password:    "somepassword",
 		},
 	)
 
@@ -120,7 +134,7 @@ func TestCreateUserSameEmail(t *testing.T) {
 	handler.ServeHTTP(rr, req)
 
 	apitest.AssertResponseError(t, rr, http.StatusBadRequest, &types.ExternalError{
-		Error: fmt.Sprintf("email already taken"),
+		Error: "email already taken",
 	})
 }
 
@@ -130,8 +144,11 @@ func TestFailingCreateUserMethod(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/users",
 		&types.CreateUserRequest{
-			Email:    "test@test.it",
-			Password: "somepassword",
+			FirstName:   "Mister",
+			LastName:    "Porter",
+			CompanyName: "Porter Technologies, Inc.",
+			Email:       "mrp@porter.run",
+			Password:    "somepassword",
 		},
 	)
 
@@ -154,8 +171,11 @@ func TestFailingCreateSessionMethod(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/users",
 		&types.CreateUserRequest{
-			Email:    "test@test.it",
-			Password: "somepassword",
+			FirstName:   "Mister",
+			LastName:    "Porter",
+			CompanyName: "Porter Technologies, Inc.",
+			Email:       "mrp@porter.run",
+			Password:    "somepassword",
 		},
 	)
 

+ 4 - 1
api/server/handlers/user/current_test.go

@@ -25,7 +25,10 @@ func TestGetCurrentUserSuccessful(t *testing.T) {
 
 	expUser := &types.GetAuthenticatedUserResponse{
 		ID:            1,
-		Email:         "test@test.it",
+		FirstName:     "Mister",
+		LastName:      "Porter",
+		CompanyName:   "Porter Technologies, Inc.",
+		Email:         "mrp@porter.run",
 		EmailVerified: true,
 	}
 

+ 4 - 1
api/server/handlers/user/delete_test.go

@@ -33,7 +33,10 @@ func TestDeleteUserSuccessful(t *testing.T) {
 
 	expUser := &types.CreateUserResponse{
 		ID:            1,
-		Email:         "test@test.it",
+		FirstName:     "Mister",
+		LastName:      "Porter",
+		CompanyName:   "Porter Technologies, Inc.",
+		Email:         "mrp@porter.run",
 		EmailVerified: true,
 	}
 

+ 1 - 1
api/server/handlers/user/email_verify_test.go

@@ -33,7 +33,7 @@ func TestEmailVerifyInitiateSuccessful(t *testing.T) {
 	}
 
 	initiateOpts := fakeNotifier.GetSendEmailVerificationLastOpts()
-	assert.Equal(t, "test@test.it", initiateOpts.Email)
+	assert.Equal(t, "mrp@porter.run", initiateOpts.Email)
 
 	// parse the url and compare
 	parsedURL, err := url.Parse(initiateOpts.URL)

+ 8 - 5
api/server/handlers/user/login_test.go

@@ -18,7 +18,7 @@ func TestLoginUserSuccessful(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/login",
 		&types.LoginUserRequest{
-			Email:    "test@test.it",
+			Email:    "mrp@porter.run",
 			Password: "hello",
 		},
 	)
@@ -36,7 +36,10 @@ func TestLoginUserSuccessful(t *testing.T) {
 
 	expUser := &types.LoginUserResponse{
 		ID:            1,
-		Email:         "test@test.it",
+		FirstName:     "Mister",
+		LastName:      "Porter",
+		CompanyName:   "Porter Technologies, Inc.",
+		Email:         "mrp@porter.run",
 		EmailVerified: true,
 	}
 
@@ -51,7 +54,7 @@ func TestLoginUserIncorrectPassword(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/login",
 		&types.LoginUserRequest{
-			Email:    "test@test.it",
+			Email:    "mrp@porter.run",
 			Password: "hello1",
 		},
 	)
@@ -105,7 +108,7 @@ func TestLoginUserEmptyPassword(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/login",
 		&types.LoginUserRequest{
-			Email:    "test@test.it",
+			Email:    "mrp@porter.run",
 			Password: "",
 		},
 	)
@@ -157,7 +160,7 @@ func TestLoginUserFailingReadUserByEmailMethod(t *testing.T) {
 		string(types.HTTPVerbPost),
 		"/api/login",
 		&types.LoginUserRequest{
-			Email:    "test@test.it",
+			Email:    "mrp@porter.run",
 			Password: "hello",
 		},
 	)

+ 4 - 1
api/server/shared/apitest/user.go

@@ -12,7 +12,10 @@ func CreateTestUser(t *testing.T, config *config.Config, verified bool) *models.
 	hashedPw, _ := bcrypt.GenerateFromPassword([]byte("hello"), 8)
 
 	user, err := config.Repo.User().CreateUser(&models.User{
-		Email:         "test@test.it",
+		FirstName:     "Mister",
+		LastName:      "Porter",
+		CompanyName:   "Porter Technologies, Inc.",
+		Email:         "mrp@porter.run",
 		Password:      string(hashedPw),
 		EmailVerified: verified,
 	})

+ 25 - 29
dashboard/src/components/ProvisionerFlow.tsx

@@ -71,45 +71,48 @@ const ProvisionerFlow: React.FC<Props> = ({
             setShowCostConfirmModal(false);
           }}>
             <Text size={16} weight={500}>
-              AWS base cost consent
+              Base AWS cost consent
             </Text>
             <Spacer height="15px" />
             <Text color="helper">
-              Porter will create resources in your existing AWS account for hosting your applications. You will be separately charged by AWS and can use your cloud credits.
-            </Text>
-            <Spacer y={1} />
-            <Text color="helper">
-              AWS base cost before cloud credits:
+              Porter will create resources in your existing AWS account for hosting applications. You will be separately charged by AWS and can use your cloud credits. Base AWS cost:
             </Text>
             <Spacer y={1} />
             <ExpandableSection
-              background="#ffffff11"
+              noWrapper
+              expandText="[+] Show details"
+              collapseText="[-] Hide details"
               Header={
                 <Cost>$315.94 / mo</Cost>
               }
               ExpandedSection={
-                <Dark>
-                  <Text>
-                    • Amazon Elastic Kubernetes Service (EKS) = $73/mo
-                    <Spacer height="15px" />
-                    • Amazon EC2:
-                    <Spacer height="15px" />
-                    <Tab />+ System workloads: t3.medium instance (2) = $60.74/mo
-                    <Spacer height="15px" />
-                    <Tab />+ Monitoring workloads: t3.large instance (1) = $60.74/mo
-                    <Spacer height="15px" />
-                    <Tab />+ Application workloads: t3.xlarge instance (1) = $121.47/mo
-                  </Text>
-                </Dark>
+                <>
+                  <Spacer height="15px" />
+                  <Fieldset background="#1b1d2688">
+                    <Text>
+                      • Amazon Elastic Kubernetes Service (EKS) = $73/mo
+                      <Spacer height="15px" />
+                      • Amazon EC2:
+                      <Spacer height="15px" />
+                      <Tab />+ System workloads: t3.medium instance (2) = $60.74/mo
+                      <Spacer height="15px" />
+                      <Tab />+ Monitoring workloads: t3.large instance (1) = $60.74/mo
+                      <Spacer height="15px" />
+                      <Tab />+ Application workloads: t3.xlarge instance (1) = $121.47/mo
+                    </Text>
+                  </Fieldset>
+                </>
               }
             />
             <Spacer y={1} />
             <Text color="helper">
-              Porter metered cost: $0.019/hr/vCPU + $0.009/hr/GB RAM.
+              Separate from the AWS cost, Porter charges based on the amount of resources that are being used. Porter pricing is as follows, prorated to the minute:
             </Text>
+            <Spacer y={1}/>
+            <Cost>$0.019/hr/vCPU + $0.009/hr/GB RAM</Cost>
             <Spacer y={1} />
             <Text color="helper">
-              All AWS resources will be automatically deleted when you delete your Porter project. Please enter the base cost ("315.94") below to proceed:
+              All AWS resources will be automatically deleted when you delete your Porter project. Please enter the AWS base cost ("315.94") below to proceed:
             </Text>
             <Spacer y={1} />
             <Input placeholder="315.94" value={confirmCost} setValue={setConfirmCost} width="100%" height="40px" />
@@ -150,13 +153,6 @@ const ProvisionerFlow: React.FC<Props> = ({
 
 export default ProvisionerFlow;
 
-const Dark = styled.div`
-  position: relative;
-  padding: 25px;
-  background: #1b1d2688;
-  font-size: 13px;
-`;
-
 const Cost = styled.div`
   font-weight: 600;
   font-size: 20px;

+ 41 - 14
dashboard/src/components/porter/ExpandableSection.tsx

@@ -1,5 +1,6 @@
 import React, { useEffect, useState } from "react";
 import styled from "styled-components";
+import Container from "./Container";
 
 type Props = {
   isInitiallyExpanded?: boolean;
@@ -7,6 +8,10 @@ type Props = {
   ExpandedSection: any;
   color?: any;
   background?: string;
+  noWrapper?: boolean;
+  expandText?: string;
+  collapseText?: string;
+  maxHeight?: string;
 };
 
 const ExpandableSection: React.FC<Props> = ({
@@ -15,6 +20,10 @@ const ExpandableSection: React.FC<Props> = ({
   ExpandedSection,
   color,
   background,
+  noWrapper,
+  expandText,
+  collapseText,
+  maxHeight,
 }) => {
   const [isExpanded, setIsExpanded] = useState(false);
   useEffect(() => {
@@ -25,15 +34,25 @@ const ExpandableSection: React.FC<Props> = ({
     <StyledExpandableSection 
       isExpanded={isExpanded}
       background={background}
+      noWrapper={noWrapper}
     >
-      <HeaderRow 
-        isExpanded={isExpanded}
-        onClick={() => setIsExpanded(!isExpanded)}
-        color={color}
-      >
-        <i className="material-icons">arrow_drop_down</i> 
-        {Header}
-      </HeaderRow>
+      {noWrapper ? (
+        <Container row>
+          {Header}
+          <ExpandButton onClick={() => setIsExpanded(!isExpanded)}>
+            {isExpanded ? collapseText : expandText}
+          </ExpandButton>
+        </Container>
+      ) : (
+        <HeaderRow 
+          isExpanded={isExpanded}
+          onClick={() => setIsExpanded(!isExpanded)}
+          color={color}
+        >
+          {!noWrapper && <i className="material-icons">arrow_drop_down</i>}
+          {Header}
+        </HeaderRow>
+      )}
       {
         isExpanded && (
           ExpandedSection
@@ -45,6 +64,13 @@ const ExpandableSection: React.FC<Props> = ({
 
 export default ExpandableSection;
 
+const ExpandButton = styled.div`
+  margin-left: 15px;
+  color: #aaaabb;
+  cursor: pointer;
+  font-size: 13px;
+`;
+
 const HeaderRow = styled.div<{ 
   isExpanded: boolean;
   color?: string;
@@ -74,16 +100,17 @@ const HeaderRow = styled.div<{
 const StyledExpandableSection = styled.div<{ 
   isExpanded: boolean;
   background?: string;
+  noWrapper?: boolean;
 }>`
   width: 100%;
-  height: ${props => props.isExpanded ? "" : "40px"};
-  max-height: 255px;
+  height: ${props => (props.isExpanded || props.noWrapper) ? "" : "40px"};
+  max-height: 300px;
   overflow: hidden;
   border-radius: 5px;
-  background: ${props => props.background || "#26292e"};
-  border: 1px solid #494b4f;
+  background: ${props => !props.noWrapper && (props.background || "#26292e")};
+  border: ${props => !props.noWrapper && "1px solid #494b4f"};
   :hover {
-    border: 1px solid #7a7b80;
+    border: ${props => !props.noWrapper && "1px solid #7a7b80"};
   }
   animation: ${props => props.isExpanded ? "expandRevisions 0.3s" : ""};
   animation-timing-function: ease-out;
@@ -92,7 +119,7 @@ const StyledExpandableSection = styled.div<{
       max-height: 40px;
     }
     to {
-      max-height: 250px;
+      max-height: 300px;
     }
   }
 `;

+ 3 - 2
dashboard/src/main/home/modals/Modal.tsx

@@ -146,8 +146,9 @@ const StyledModal = styled.div<{
   z-index: 999;
   font-size: 13px;
   border-radius: 10px;
-  background: #202227;
-  border: 1px solid #ffffff55;
+  background: #42444944;
+  backdrop-filter: saturate(150%) blur(10px);
+  border: 1px solid #494b4f;
   overflow: auto;
   color: #ffffff;
   animation: floatInModal 0.5s 0s;