(
sess *provisionersdk.Session, request *provisionersdk.InitRequest, canceledOrComplete <-chan struct{},
)
| 69 | } |
| 70 | |
| 71 | func (s *server) Init( |
| 72 | sess *provisionersdk.Session, request *provisionersdk.InitRequest, canceledOrComplete <-chan struct{}, |
| 73 | ) *proto.InitComplete { |
| 74 | ctx, span := s.startTrace(sess.Context(), tracing.FuncName()) |
| 75 | defer span.End() |
| 76 | ctx, cancel, killCtx, kill := s.setupContexts(ctx, canceledOrComplete) |
| 77 | defer cancel() |
| 78 | defer kill() |
| 79 | |
| 80 | e := s.executor(sess.Files, database.ProvisionerJobTimingStageInit) |
| 81 | if err := e.checkMinVersion(ctx); err != nil { |
| 82 | return provisionersdk.InitErrorf("%s", err.Error()) |
| 83 | } |
| 84 | logTerraformEnvVars(sess) |
| 85 | |
| 86 | // TODO: These logs should probably be streamed back to the provisioner runner. |
| 87 | err := sess.Files.ExtractArchive(ctx, s.logger, afero.NewOsFs(), request.GetTemplateSourceArchive(), request.ModuleArchive) |
| 88 | if err != nil { |
| 89 | return provisionersdk.InitErrorf("extract template archive: %s", err) |
| 90 | } |
| 91 | |
| 92 | err = CleanStaleTerraformPlugins(sess.Context(), s.cachePath, afero.NewOsFs(), time.Now(), s.logger) |
| 93 | if err != nil { |
| 94 | return provisionersdk.InitErrorf("unable to clean stale Terraform plugins: %s", err) |
| 95 | } |
| 96 | |
| 97 | s.logger.Debug(ctx, "running terraform initialization") |
| 98 | endStage := e.timings.startStage(database.ProvisionerJobTimingStageInit) |
| 99 | err = e.init(ctx, killCtx, sess) |
| 100 | endStage(err) |
| 101 | if err != nil { |
| 102 | s.logger.Debug(ctx, "init failed", slog.Error(err)) |
| 103 | |
| 104 | // Special handling for "text file busy" c.f. https://github.com/coder/coder/issues/14726 |
| 105 | // We believe this might be due to some race condition that prevents the |
| 106 | // terraform-provider-coder process from exiting. When terraform tries to install the |
| 107 | // provider during this init, it copies over the local cache. Normally this isn't an issue, |
| 108 | // but if the terraform-provider-coder process is still running from a previous build, Linux |
| 109 | // returns "text file busy" error when attempting to open the file. |
| 110 | // |
| 111 | // Capturing the stack trace from the process should help us figure out why it has not |
| 112 | // exited. We'll drop these diagnostics in a CRITICAL log so that operators are likely to |
| 113 | // notice, and also because it indicates this provisioner could be permanently broken and |
| 114 | // require a restart. |
| 115 | var errTFB *textFileBusyError |
| 116 | if xerrors.As(err, &errTFB) { |
| 117 | stacktrace := tryGettingCoderProviderStacktrace(sess) |
| 118 | s.logger.Critical(ctx, "init: text file busy", |
| 119 | slog.Error(errTFB), |
| 120 | slog.F("stderr", errTFB.stderr), |
| 121 | slog.F("provider_coder_stacktrace", stacktrace), |
| 122 | ) |
| 123 | } |
| 124 | return provisionersdk.InitErrorf("initialize terraform: %s", err) |
| 125 | } |
| 126 | |
| 127 | modules, err := getModules(sess.Files) |
| 128 | if err != nil { |
nothing calls this directly
no test coverage detected