postLicense adds a new Enterprise license to the cluster. We allow multiple different licenses in the cluster at one time for several reasons: 1. Upgrades --- if the license format changes from one version of Coder to the next, during a rolling update you will have different Coder servers that nee
(rw http.ResponseWriter, r *http.Request)
| 64 | // @Success 201 {object} codersdk.License |
| 65 | // @Router /api/v2/licenses [post] |
| 66 | func (api *API) postLicense(rw http.ResponseWriter, r *http.Request) { |
| 67 | var ( |
| 68 | ctx = r.Context() |
| 69 | auditor = api.AGPL.Auditor.Load() |
| 70 | aReq, commitAudit = audit.InitRequest[database.License](rw, &audit.RequestParams{ |
| 71 | Audit: *auditor, |
| 72 | Log: api.Logger, |
| 73 | Request: r, |
| 74 | Action: database.AuditActionCreate, |
| 75 | }) |
| 76 | ) |
| 77 | defer commitAudit() |
| 78 | |
| 79 | if !api.AGPL.Authorize(r, policy.ActionCreate, rbac.ResourceLicense) { |
| 80 | httpapi.Forbidden(rw) |
| 81 | return |
| 82 | } |
| 83 | |
| 84 | var addLicense codersdk.AddLicenseRequest |
| 85 | if !httpapi.Read(ctx, rw, r, &addLicense) { |
| 86 | return |
| 87 | } |
| 88 | |
| 89 | claims, err := license.ParseClaimsIgnoreNbf(addLicense.License, api.LicenseKeys) |
| 90 | if err != nil { |
| 91 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 92 | Message: "Invalid license", |
| 93 | Detail: err.Error(), |
| 94 | }) |
| 95 | return |
| 96 | } |
| 97 | |
| 98 | id, err := uuid.Parse(claims.ID) |
| 99 | if err != nil { |
| 100 | // If no uuid is in the license, we generate a random uuid. |
| 101 | // This is not ideal, and this should be fixed to require a uuid |
| 102 | // for all licenses. We require this patch to support older licenses. |
| 103 | // TODO: In the future (April 2023?) we should remove this and reissue |
| 104 | // old licenses with a uuid. |
| 105 | id = uuid.New() |
| 106 | } |
| 107 | if len(claims.DeploymentIDs) > 0 && !slices.Contains(claims.DeploymentIDs, api.AGPL.DeploymentID) { |
| 108 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 109 | Message: "License cannot be used on this deployment!", |
| 110 | Detail: fmt.Sprintf("The provided license is locked to the following deployments: %q. "+ |
| 111 | "Your deployment identifier is %q. Please contact sales.", claims.DeploymentIDs, api.AGPL.DeploymentID), |
| 112 | }) |
| 113 | return |
| 114 | } |
| 115 | |
| 116 | dl, err := api.Database.InsertLicense(ctx, database.InsertLicenseParams{ |
| 117 | UploadedAt: dbtime.Now(), |
| 118 | JWT: addLicense.License, |
| 119 | Exp: claims.ExpiresAt.Time, |
| 120 | UUID: id, |
| 121 | }) |
| 122 | if err != nil { |
| 123 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
nothing calls this directly
no test coverage detected