github.com/henvic/wedeploycli@v1.7.6-0.20200319005353-3630f582f284/command/deploy/deploy.go (about) 1 package deploy 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "os" 9 "path/filepath" 10 "time" 11 12 "github.com/hashicorp/errwrap" 13 "github.com/henvic/ctxsignal" 14 "github.com/henvic/wedeploycli/cmdflagsfromhost" 15 "github.com/henvic/wedeploycli/color" 16 "github.com/henvic/wedeploycli/command/deploy/internal/getproject" 17 deployremote "github.com/henvic/wedeploycli/command/deploy/remote" 18 "github.com/henvic/wedeploycli/command/internal/we" 19 "github.com/henvic/wedeploycli/deployment" 20 "github.com/henvic/wedeploycli/jsonerror" 21 "github.com/henvic/wedeploycli/logs" 22 "github.com/henvic/wedeploycli/services" 23 "github.com/spf13/cobra" 24 ) 25 26 var setupHost = cmdflagsfromhost.SetupHost{ 27 Pattern: cmdflagsfromhost.RegionPattern | cmdflagsfromhost.FullHostPattern, 28 29 Requires: cmdflagsfromhost.Requires{ 30 Auth: true, 31 Project: true, 32 }, 33 34 UseProjectFromWorkingDirectory: true, 35 36 AllowMissingProject: true, 37 PromptMissingProject: true, 38 HideServicesPrompt: true, 39 AllowCreateProjectOnPrompt: true, 40 } 41 42 var ( 43 params deployment.Params 44 metadata string 45 follow bool 46 experimental bool 47 ) 48 49 // DeployCmd runs services 50 var DeployCmd = &cobra.Command{ 51 Use: "deploy", 52 Short: "Deploy your services", 53 Example: ` lcp deploy 54 lcp deploy https://gitlab.com/user/repo 55 lcp deploy user/repo#branch`, 56 Args: cobra.MaximumNArgs(1), 57 PreRunE: preRun, 58 RunE: run, 59 } 60 61 func checkMetadata() error { 62 if metadata == "" { 63 return nil 64 } 65 66 if err := json.Unmarshal([]byte(metadata), &deployment.Metadata{}); err != nil { 67 return errwrap.Wrapf( 68 "error parsing metadata: {{err}}", 69 jsonerror.FriendlyUnmarshal(err)) 70 } 71 72 return nil 73 } 74 75 func preRun(cmd *cobra.Command, args []string) error { 76 params.Quiet = params.Quiet || params.SkipProgress // be quieter on skip progress as well 77 params.Metadata = json.RawMessage(metadata) 78 79 if err := checkMetadata(); err != nil { 80 return err 81 } 82 83 if err := maybePreRunDeployFromGitRepo(cmd, args); err != nil { 84 return err 85 } 86 87 return setupHost.Process(context.Background(), we.Context()) 88 } 89 90 func run(cmd *cobra.Command, args []string) (err error) { 91 params.Remote = setupHost.Remote() 92 93 var sil services.ServiceInfoList 94 switch { 95 case len(args) != 0: 96 sil, err = fromGitRepo(args[0]) 97 default: 98 sil, err = local() 99 } 100 101 if err != nil || !follow { 102 return err 103 } 104 105 return followLogs(sil) 106 } 107 108 func handleCopyPackage() (err error) { 109 if params.CopyPackage == "" { 110 return nil 111 } 112 113 if _, err = os.Stat(params.CopyPackage); err != nil { 114 return errwrap.Wrapf("invalid --copy-pkg value: {{err}}", err) 115 } 116 117 params.CopyPackage, err = filepath.Abs(params.CopyPackage) 118 return err 119 } 120 121 func local() (sil services.ServiceInfoList, err error) { 122 if err = handleCopyPackage(); err != nil { 123 return sil, err 124 } 125 126 params.ProjectID = setupHost.Project() 127 params.Region = setupHost.Region() 128 params.ServiceID = setupHost.Service() 129 130 var rd = &deployremote.RemoteDeployment{ 131 Params: params, 132 Experimental: experimental, 133 } 134 135 ctx, cancel := ctxsignal.WithTermination(context.Background()) 136 defer cancel() 137 138 var f deployremote.Feedback 139 f, err = rd.Run(ctx) 140 return f.Services, err 141 } 142 143 func maybePreRunDeployFromGitRepo(cmd *cobra.Command, args []string) error { 144 if len(args) != 1 { 145 return nil 146 } 147 148 if s, _ := cmd.Flags().GetString("service"); s != "" { 149 return errors.New("deploying with custom service ids isn't supported using git repositories") 150 } 151 152 if params.CopyPackage != "" { 153 return errors.New("can't create a local package when deploying with a git remote") 154 } 155 156 return nil 157 } 158 159 func fromGitRepo(repo string) (services.ServiceInfoList, error) { 160 if params.Image != "" { 161 return nil, errors.New("overwriting image when deploying from a git repository is not supported") 162 } 163 164 if metadata != "" { 165 return nil, errors.New("using metadata when deploying from a git repository is not supported") 166 } 167 168 var err error 169 params.Region = setupHost.Region() 170 params.ProjectID, err = getproject.MaybeID(setupHost.Project(), params.Region) 171 172 if err != nil { 173 return nil, err 174 } 175 176 return deployment.DeployFromGitRepository(context.Background(), we.Context(), params, repo) 177 } 178 179 func followLogs(sil services.ServiceInfoList) error { 180 now := time.Now() 181 since := 10 * time.Second 182 // BUG(henvic): this preliminary version only loads logs from 10s ago onwards. 183 184 if len(sil) == 0 { 185 panic("no services found to list logs") 186 } 187 188 var projectID = sil[0].ProjectID 189 190 f := &logs.Filter{ 191 Project: projectID, 192 Services: sil.GetIDs(), 193 194 Since: fmt.Sprintf("%v000000000", now.Add(-since).Unix()), 195 } 196 197 watcher := &logs.Watcher{ 198 Filter: f, 199 } 200 201 ctx, cancel := ctxsignal.WithTermination(context.Background()) 202 defer cancel() 203 204 fmt.Println() 205 fmt.Println(color.Format(color.FgBlue, color.Bold, 206 fmt.Sprintf("Showing logs from %v ago onwards.", since))) 207 fmt.Printf("You can exit anytime.\n\n") 208 time.Sleep(220 * time.Millisecond) 209 210 watcher.Watch(ctx, we.Context()) 211 212 if _, err := ctxsignal.Closed(ctx); err == nil { 213 fmt.Println() 214 } 215 216 return nil 217 } 218 219 func init() { 220 DeployCmd.Flags().StringVar(¶ms.Image, "image", "", "Use different image for service") 221 DeployCmd.Flags().StringVar(&metadata, "metadata", "", "Metadata in JSON") 222 DeployCmd.Flags().BoolVar(¶ms.OnlyBuild, "only-build", false, 223 "Skip deployment (only build)") 224 DeployCmd.Flags().BoolVar(¶ms.SkipProgress, "skip-progress", false, 225 "Skip watching deployment progress, quiet") 226 DeployCmd.Flags().BoolVarP(¶ms.Quiet, "quiet", "q", false, 227 "Suppress progress animations") 228 DeployCmd.Flags().BoolVar(&follow, "follow", false, 229 "Follow logs after deployment") 230 DeployCmd.Flags().BoolVar( 231 &experimental, 232 "experimental", false, "Enable experimental deployment") 233 DeployCmd.Flags().StringVar(¶ms.CopyPackage, "copy-pkg", "", 234 "Path to copy the deployment package to (for debugging)") 235 _ = DeployCmd.Flags().MarkHidden("metadata") 236 _ = DeployCmd.Flags().MarkHidden("follow") 237 _ = DeployCmd.Flags().MarkHidden("experimental") 238 _ = DeployCmd.Flags().MarkHidden("copy-pkg") 239 240 setupHost.Init(DeployCmd) 241 }