|
4 | 4 | "fmt" |
5 | 5 | "os" |
6 | 6 | "path/filepath" |
| 7 | + "strconv" |
| 8 | + "strings" |
7 | 9 | "time" |
8 | 10 |
|
9 | 11 | "github.com/flatrun/agent/pkg/models" |
@@ -102,9 +104,14 @@ func (d *Discovery) GetDeployment(name string) (*models.Deployment, error) { |
102 | 104 | } |
103 | 105 |
|
104 | 106 | metadataPath := filepath.Join(dirPath, "service.yml") |
105 | | - if metadata, err := d.loadMetadata(metadataPath); err == nil { |
106 | | - deployment.Metadata = metadata |
| 107 | + metadata, err := d.loadMetadata(metadataPath) |
| 108 | + if err != nil { |
| 109 | + metadata = d.generateMetadataFromCompose(composePath, name) |
| 110 | + if metadata != nil { |
| 111 | + _ = d.SaveMetadata(name, metadata) |
| 112 | + } |
107 | 113 | } |
| 114 | + deployment.Metadata = metadata |
108 | 115 |
|
109 | 116 | if services, err := d.parseComposeServices(composePath); err == nil { |
110 | 117 | deployment.Services = services |
@@ -203,10 +210,38 @@ func (d *Discovery) CreateDeployment(name string, composeContent string) error { |
203 | 210 | return err |
204 | 211 | } |
205 | 212 |
|
| 213 | + // Ensure compose file has a name attribute for project identification |
| 214 | + composeContent = d.ensureComposeName(name, composeContent) |
| 215 | + |
206 | 216 | composePath := filepath.Join(dirPath, "docker-compose.yml") |
207 | 217 | return os.WriteFile(composePath, []byte(composeContent), 0644) |
208 | 218 | } |
209 | 219 |
|
| 220 | +// ensureComposeName adds or updates the name attribute in a compose file |
| 221 | +func (d *Discovery) ensureComposeName(name string, content string) string { |
| 222 | + var compose map[string]interface{} |
| 223 | + if err := yaml.Unmarshal([]byte(content), &compose); err != nil { |
| 224 | + // If parsing fails, prepend name manually |
| 225 | + return fmt.Sprintf("name: %s\n%s", name, content) |
| 226 | + } |
| 227 | + |
| 228 | + // Check if name already exists |
| 229 | + if _, exists := compose["name"]; exists { |
| 230 | + return content |
| 231 | + } |
| 232 | + |
| 233 | + // Add name attribute |
| 234 | + compose["name"] = name |
| 235 | + |
| 236 | + // Re-marshal with name included |
| 237 | + data, err := yaml.Marshal(compose) |
| 238 | + if err != nil { |
| 239 | + return fmt.Sprintf("name: %s\n%s", name, content) |
| 240 | + } |
| 241 | + |
| 242 | + return string(data) |
| 243 | +} |
| 244 | + |
210 | 245 | func (d *Discovery) DeleteDeployment(name string) error { |
211 | 246 | dirPath := filepath.Join(d.basePath, name) |
212 | 247 | return os.RemoveAll(dirPath) |
@@ -266,3 +301,68 @@ func (d *Discovery) DeleteMetadata(name string) error { |
266 | 301 |
|
267 | 302 | return os.Remove(metadataPath) |
268 | 303 | } |
| 304 | + |
| 305 | +func (d *Discovery) generateMetadataFromCompose(composePath, name string) *models.ServiceMetadata { |
| 306 | + data, err := os.ReadFile(composePath) |
| 307 | + if err != nil { |
| 308 | + return nil |
| 309 | + } |
| 310 | + |
| 311 | + var compose composeFile |
| 312 | + if err := yaml.Unmarshal(data, &compose); err != nil { |
| 313 | + return nil |
| 314 | + } |
| 315 | + |
| 316 | + metadata := &models.ServiceMetadata{ |
| 317 | + Name: name, |
| 318 | + Type: "", |
| 319 | + Networking: models.NetworkingConfig{ |
| 320 | + Expose: false, |
| 321 | + Protocol: "http", |
| 322 | + ProxyType: "http", |
| 323 | + }, |
| 324 | + SSL: models.SSLConfig{ |
| 325 | + Enabled: false, |
| 326 | + AutoCert: false, |
| 327 | + }, |
| 328 | + HealthCheck: models.HealthCheckConfig{ |
| 329 | + Path: "/", |
| 330 | + Interval: "30s", |
| 331 | + }, |
| 332 | + } |
| 333 | + |
| 334 | + for _, svc := range compose.Services { |
| 335 | + if len(svc.Ports) > 0 { |
| 336 | + portStr := d.parsePort(svc.Ports[0]) |
| 337 | + if portStr != "" { |
| 338 | + port := d.extractContainerPort(portStr) |
| 339 | + if port > 0 { |
| 340 | + metadata.Networking.ContainerPort = port |
| 341 | + } |
| 342 | + } |
| 343 | + break |
| 344 | + } |
| 345 | + } |
| 346 | + |
| 347 | + return metadata |
| 348 | +} |
| 349 | + |
| 350 | +func (d *Discovery) extractContainerPort(portStr string) int { |
| 351 | + parts := strings.Split(portStr, ":") |
| 352 | + var portPart string |
| 353 | + if len(parts) == 2 { |
| 354 | + portPart = parts[1] |
| 355 | + } else if len(parts) == 1 { |
| 356 | + portPart = parts[0] |
| 357 | + } else { |
| 358 | + return 0 |
| 359 | + } |
| 360 | + |
| 361 | + portPart = strings.Split(portPart, "/")[0] |
| 362 | + |
| 363 | + port, err := strconv.Atoi(portPart) |
| 364 | + if err != nil { |
| 365 | + return 0 |
| 366 | + } |
| 367 | + return port |
| 368 | +} |
0 commit comments