deployments.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package dbstore
  2. import (
  3. "context"
  4. "database/sql"
  5. "fmt"
  6. "git.linuxforward.com/byop/byop-engine/models"
  7. "github.com/pkg/errors"
  8. )
  9. // Deployment operations
  10. func (s *SQLiteStore) CreateDeployment(ctx context.Context, deployment models.Deployment) (int, error) {
  11. query := `INSERT INTO deployments (app_id, client_id, name, description, environment, status, url, config, deployed_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
  12. deployedAt := sql.NullTime{}
  13. if !deployment.DeployedAt.IsZero() {
  14. deployedAt.Time = deployment.DeployedAt
  15. deployedAt.Valid = true
  16. }
  17. result, err := s.db.ExecContext(ctx, query, deployment.AppId, deployment.ClientID, deployment.Name, deployment.Description, deployment.Environment, deployment.Status, deployment.URL, deployment.Config, deployedAt)
  18. if err != nil {
  19. return 0, models.NewErrInternalServer("failed to create deployment", err)
  20. }
  21. id, err := result.LastInsertId()
  22. if err != nil {
  23. return 0, models.NewErrInternalServer("failed to get last insert ID for deployment", err)
  24. }
  25. return int(id), nil
  26. }
  27. func (s *SQLiteStore) GetDeploymentsByAppID(ctx context.Context, appID int) ([]*models.Deployment, error) {
  28. query := `SELECT id, app_id, client_id, name, description, environment, status, url, config, deployed_at, created_at, updated_at FROM deployments WHERE app_id = ?`
  29. rows, err := s.db.QueryContext(ctx, query, appID)
  30. if err != nil {
  31. return nil, models.NewErrInternalServer(fmt.Sprintf("failed to query deployments for app ID %d", appID), err)
  32. }
  33. defer rows.Close()
  34. var deployments []*models.Deployment
  35. for rows.Next() {
  36. var deployment models.Deployment
  37. var deployedAt sql.NullTime
  38. err := rows.Scan(&deployment.ID, &deployment.AppId, &deployment.ClientID, &deployment.Name, &deployment.Description, &deployment.Environment, &deployment.Status, &deployment.URL, &deployment.Config, &deployedAt, &deployment.CreatedAt, &deployment.UpdatedAt)
  39. if err != nil {
  40. return nil, models.NewErrInternalServer("failed to scan deployment row", err)
  41. }
  42. if deployedAt.Valid {
  43. deployment.DeployedAt = deployedAt.Time
  44. }
  45. deployments = append(deployments, &deployment)
  46. }
  47. if err = rows.Err(); err != nil {
  48. return nil, models.NewErrInternalServer(fmt.Sprintf("error iterating deployment rows for app ID %d", appID), err)
  49. }
  50. return deployments, nil
  51. }
  52. func (s *SQLiteStore) GetAllDeployments(ctx context.Context) ([]*models.Deployment, error) {
  53. query := `SELECT id, app_id, client_id, name, description, environment, status, url, config, deployed_at, created_at, updated_at FROM deployments`
  54. rows, err := s.db.QueryContext(ctx, query)
  55. if err != nil {
  56. return nil, models.NewErrInternalServer("failed to query all deployments", err)
  57. }
  58. defer rows.Close()
  59. var deployments []*models.Deployment
  60. for rows.Next() {
  61. var deployment models.Deployment
  62. var deployedAt sql.NullTime
  63. err := rows.Scan(&deployment.ID, &deployment.AppId, &deployment.ClientID, &deployment.Name, &deployment.Description, &deployment.Environment, &deployment.Status, &deployment.URL, &deployment.Config, &deployedAt, &deployment.CreatedAt, &deployment.UpdatedAt)
  64. if err != nil {
  65. return nil, models.NewErrInternalServer("failed to scan deployment row", err)
  66. }
  67. if deployedAt.Valid {
  68. deployment.DeployedAt = deployedAt.Time
  69. }
  70. deployments = append(deployments, &deployment)
  71. }
  72. if err = rows.Err(); err != nil {
  73. return nil, models.NewErrInternalServer("error iterating all deployment rows", err)
  74. }
  75. return deployments, nil
  76. }
  77. func (s *SQLiteStore) GetDeploymentByID(ctx context.Context, id int) (*models.Deployment, error) {
  78. var deployment models.Deployment
  79. var deployedAt sql.NullTime
  80. query := `SELECT id, app_id, client_id, name, description, environment, status, url, config, deployed_at, created_at, updated_at FROM deployments WHERE id = ?`
  81. err := s.db.QueryRowContext(ctx, query, id).Scan(&deployment.ID, &deployment.AppId, &deployment.ClientID, &deployment.Name, &deployment.Description, &deployment.Environment, &deployment.Status, &deployment.URL, &deployment.Config, &deployedAt, &deployment.CreatedAt, &deployment.UpdatedAt)
  82. if err != nil {
  83. if errors.Is(err, sql.ErrNoRows) {
  84. return nil, models.NewErrNotFound(fmt.Sprintf("deployment with ID %d not found", id), err)
  85. }
  86. return nil, models.NewErrInternalServer(fmt.Sprintf("failed to get deployment with ID %d", id), err)
  87. }
  88. if deployedAt.Valid {
  89. deployment.DeployedAt = deployedAt.Time
  90. }
  91. return &deployment, nil
  92. }
  93. func (s *SQLiteStore) UpdateDeployment(ctx context.Context, deployment *models.Deployment) error {
  94. deployedAt := sql.NullTime{}
  95. if !deployment.DeployedAt.IsZero() {
  96. deployedAt.Time = deployment.DeployedAt
  97. deployedAt.Valid = true
  98. }
  99. query := `UPDATE deployments SET app_id = ?, client_id = ?, name = ?, description = ?, environment = ?, status = ?, url = ?, config = ?, deployed_at = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?`
  100. result, err := s.db.ExecContext(ctx, query, deployment.AppId, deployment.ClientID, deployment.Name, deployment.Description, deployment.Environment, deployment.Status, deployment.URL, deployment.Config, deployedAt, deployment.ID)
  101. if err != nil {
  102. return models.NewErrInternalServer(fmt.Sprintf("failed to update deployment with ID %d", deployment.ID), err)
  103. }
  104. rowsAffected, err := result.RowsAffected()
  105. if err != nil {
  106. return models.NewErrInternalServer(fmt.Sprintf("failed to get rows affected for deployment update ID %d", deployment.ID), err)
  107. }
  108. if rowsAffected == 0 {
  109. return models.NewErrNotFound(fmt.Sprintf("deployment with ID %d not found for update", deployment.ID), nil)
  110. }
  111. return nil
  112. }
  113. // DeleteDeployment deletes a deployment by ID with verification checks
  114. func (s *SQLiteStore) DeleteDeployment(ctx context.Context, id int) error {
  115. // First check if the deployment exists
  116. deployment, err := s.GetDeploymentByID(ctx, id)
  117. if err != nil {
  118. return err // GetDeploymentByID already returns custom errors
  119. }
  120. // Check if deployment is currently running
  121. if deployment.Status == "running" || deployment.Status == "deploying" {
  122. return models.NewErrConflict(fmt.Sprintf("cannot delete deployment: it is currently %s. Please stop the deployment first", deployment.Status), nil)
  123. }
  124. // Proceed with deletion
  125. query := `DELETE FROM deployments WHERE id = ?`
  126. result, err := s.db.ExecContext(ctx, query, id)
  127. if err != nil {
  128. return models.NewErrInternalServer(fmt.Sprintf("failed to delete deployment with ID %d", id), err)
  129. }
  130. rowsAffected, err := result.RowsAffected()
  131. if err != nil {
  132. return models.NewErrInternalServer(fmt.Sprintf("failed to get rows affected for deployment deletion ID %d", id), err)
  133. }
  134. if rowsAffected == 0 {
  135. // This case should ideally be caught by GetDeploymentByID earlier, but as a safeguard:
  136. return models.NewErrNotFound(fmt.Sprintf("deployment with ID %d not found for deletion", id), nil)
  137. }
  138. return nil
  139. }
  140. // GetDeploymentsByClientID retrieves all deployments for a given client ID
  141. func (s *SQLiteStore) GetDeploymentsByClientID(ctx context.Context, clientID int) ([]*models.Deployment, error) {
  142. query := `SELECT id, app_id, client_id, name, description, environment, status, url, config, deployed_at, created_at, updated_at FROM deployments WHERE client_id = ?`
  143. rows, err := s.db.QueryContext(ctx, query, clientID)
  144. if err != nil {
  145. return nil, models.NewErrInternalServer(fmt.Sprintf("failed to query deployments for client ID %d", clientID), err)
  146. }
  147. defer rows.Close()
  148. var deployments []*models.Deployment
  149. for rows.Next() {
  150. var deployment models.Deployment
  151. var deployedAt sql.NullTime
  152. err := rows.Scan(&deployment.ID, &deployment.AppId, &deployment.ClientID, &deployment.Name, &deployment.Description, &deployment.Environment, &deployment.Status, &deployment.URL, &deployment.Config, &deployedAt, &deployment.CreatedAt, &deployment.UpdatedAt)
  153. if err != nil {
  154. return nil, models.NewErrInternalServer("failed to scan deployment row for client", err)
  155. }
  156. if deployedAt.Valid {
  157. deployment.DeployedAt = deployedAt.Time
  158. }
  159. deployments = append(deployments, &deployment)
  160. }
  161. if err = rows.Err(); err != nil {
  162. return nil, models.NewErrInternalServer(fmt.Sprintf("error iterating deployment rows for client ID %d", clientID), err)
  163. }
  164. return deployments, nil
  165. }
  166. // GetDeploymentsByUserID retrieves all deployments for a given user ID
  167. // This assumes a link between deployments and users, which might not be direct.
  168. // If deployments are linked via apps, and apps via users, this query would need to be more complex
  169. // or a direct user_id column added to deployments.
  170. // For now, assuming a direct user_id on deployments or this is handled via a join in a more complex setup.
  171. // If UserID is not directly on the deployments table, this will need adjustment.
  172. // For this example, let's assume there's a user_id on the apps table, and we join through it.
  173. // This requires an `apps` table with `user_id` and `id` (app_id in deployments).
  174. func (s *SQLiteStore) GetDeploymentsByUserID(ctx context.Context, userID int) ([]*models.Deployment, error) {
  175. // This query assumes deployments are linked to users via the 'apps' table.
  176. // Adjust if your schema is different (e.g., direct user_id on deployments).
  177. query := `
  178. SELECT d.id, d.app_id, d.client_id, d.name, d.description, d.environment, d.status, d.url, d.config, d.deployed_at, d.created_at, d.updated_at
  179. FROM deployments d
  180. INNER JOIN apps a ON d.app_id = a.id
  181. WHERE a.user_id = ?`
  182. rows, err := s.db.QueryContext(ctx, query, userID)
  183. if err != nil {
  184. return nil, models.NewErrInternalServer(fmt.Sprintf("failed to query deployments for user ID %d", userID), err)
  185. }
  186. defer rows.Close()
  187. var deployments []*models.Deployment
  188. for rows.Next() {
  189. var deployment models.Deployment
  190. var deployedAt sql.NullTime
  191. err := rows.Scan(&deployment.ID, &deployment.AppId, &deployment.ClientID, &deployment.Name, &deployment.Description, &deployment.Environment, &deployment.Status, &deployment.URL, &deployment.Config, &deployedAt, &deployment.CreatedAt, &deployment.UpdatedAt)
  192. if err != nil {
  193. return nil, models.NewErrInternalServer("failed to scan deployment row for user", err)
  194. }
  195. if deployedAt.Valid {
  196. deployment.DeployedAt = deployedAt.Time
  197. }
  198. deployments = append(deployments, &deployment)
  199. }
  200. if err = rows.Err(); err != nil {
  201. return nil, models.NewErrInternalServer(fmt.Sprintf("error iterating deployment rows for user ID %d", userID), err)
  202. }
  203. return deployments, nil
  204. }