github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/rpc/transform.go (about) 1 package rpc 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "time" 8 9 enginetypes "github.com/projecteru2/core/engine/types" 10 "github.com/projecteru2/core/log" 11 resourcetypes "github.com/projecteru2/core/resource/types" 12 pb "github.com/projecteru2/core/rpc/gen" 13 "github.com/projecteru2/core/types" 14 "github.com/projecteru2/core/utils" 15 16 "golang.org/x/net/context" 17 ) 18 19 func toRPCServiceStatus(status types.ServiceStatus) *pb.ServiceStatus { 20 return &pb.ServiceStatus{ 21 Addresses: status.Addresses, 22 IntervalInSecond: int64(status.Interval / time.Second), 23 } 24 } 25 26 func toRPCPod(p *types.Pod) *pb.Pod { 27 return &pb.Pod{Name: p.Name, Desc: p.Desc} 28 } 29 30 func toRPCNetwork(n *enginetypes.Network) *pb.Network { 31 return &pb.Network{Name: n.Name, Subnets: n.Subnets} 32 } 33 34 func toRPCNode(n *types.Node) *pb.Node { 35 node := &pb.Node{ 36 Name: n.Name, 37 Endpoint: n.Endpoint, 38 Podname: n.Podname, 39 Available: n.Available, 40 Labels: n.Labels, 41 Info: n.NodeInfo, 42 Bypass: n.Bypass, 43 Test: n.Test, 44 ResourceCapacity: toRPCResources(n.ResourceInfo.Capacity), 45 ResourceUsage: toRPCResources(n.ResourceInfo.Usage), 46 } 47 return node 48 } 49 50 func toRPCResources(v any) string { 51 body, _ := json.Marshal(v) 52 return string(body) 53 } 54 55 func toRPCEngine(e *enginetypes.Info) *pb.Engine { 56 return &pb.Engine{ 57 Type: e.Type, 58 } 59 } 60 61 func toRPCNodeResource(nr *types.NodeResourceInfo) *pb.NodeResource { 62 return &pb.NodeResource{ 63 Name: nr.Name, 64 Diffs: nr.Diffs, 65 ResourceCapacity: toRPCResources(nr.Capacity), 66 ResourceUsage: toRPCResources(nr.Usage), 67 } 68 } 69 70 func toRPCBuildImageMessage(b *types.BuildImageMessage) *pb.BuildImageMessage { 71 return &pb.BuildImageMessage{ 72 Id: b.ID, 73 Status: b.Status, 74 Progress: b.Progress, 75 Error: b.Error, 76 Stream: b.Stream, 77 ErrorDetail: &pb.ErrorDetail{ 78 Code: int64(b.ErrorDetail.Code), 79 Message: b.ErrorDetail.Message, 80 }, 81 } 82 } 83 84 func toCoreListNodesOptions(b *pb.ListNodesOptions) *types.ListNodesOptions { 85 return &types.ListNodesOptions{ 86 Podname: b.Podname, 87 Labels: b.Labels, 88 All: b.All, 89 CallInfo: !b.SkipInfo, 90 } 91 } 92 93 func toCoreCopyOptions(b *pb.CopyOptions) *types.CopyOptions { 94 r := &types.CopyOptions{Targets: map[string][]string{}} 95 for cid, paths := range b.Targets { 96 r.Targets[cid] = []string{} 97 r.Targets[cid] = append(r.Targets[cid], paths.Paths...) 98 } 99 return r 100 } 101 102 func toCoreSendOptions(b *pb.SendOptions) (*types.SendOptions, error) { //nolint 103 files := []types.LinuxFile{} 104 for filename, content := range b.Data { 105 files = append(files, types.LinuxFile{ 106 Content: content, 107 Filename: filename, 108 UID: int(b.Owners[filename].GetUid()), 109 GID: int(b.Owners[filename].GetGid()), 110 Mode: b.Modes[filename].GetMode(), 111 }) 112 } 113 return &types.SendOptions{ 114 IDs: b.IDs, 115 Files: files, 116 }, nil 117 } 118 119 func toCoreAddNodeOptions(b *pb.AddNodeOptions) *types.AddNodeOptions { 120 r := &types.AddNodeOptions{ 121 Nodename: b.Nodename, 122 Endpoint: b.Endpoint, 123 Podname: b.Podname, 124 Ca: b.Ca, 125 Cert: b.Cert, 126 Key: b.Key, 127 Labels: b.Labels, 128 Resources: toCoreResources(b.Resources), 129 Test: b.Test, 130 } 131 return r 132 } 133 134 func toCoreSetNodeOptions(b *pb.SetNodeOptions) (*types.SetNodeOptions, error) { //nolint 135 r := &types.SetNodeOptions{ 136 Nodename: b.Nodename, 137 Endpoint: b.Endpoint, 138 Ca: b.Ca, 139 Cert: b.Cert, 140 Key: b.Key, 141 WorkloadsDown: b.WorkloadsDown, 142 Resources: toCoreResources(b.Resources), 143 Delta: b.Delta, 144 Labels: b.Labels, 145 Bypass: types.TriOptions(b.Bypass), 146 } 147 return r, nil 148 } 149 150 func toCoreBuildOptions(b *pb.BuildImageOptions) (*types.BuildOptions, error) { 151 var builds *types.Builds 152 if b.GetBuilds() != nil { 153 if len(b.GetBuilds().Stages) == 0 { 154 return nil, types.ErrNoBuildsInSpec 155 } 156 builds = &types.Builds{ 157 Stages: b.GetBuilds().Stages, 158 } 159 builds.Builds = map[string]*types.Build{} 160 for stage, p := range b.GetBuilds().Builds { 161 if p == nil { 162 return nil, types.ErrNoBuildSpec 163 } 164 builds.Builds[stage] = &types.Build{ 165 Base: p.Base, 166 Repo: p.Repo, 167 Version: p.Version, 168 Dir: p.Dir, 169 Submodule: p.Submodule || false, 170 Security: p.Security || false, 171 Commands: p.Commands, 172 Envs: p.Envs, 173 Args: p.Args, 174 Labels: p.Labels, 175 Artifacts: p.Artifacts, 176 Cache: p.Cache, 177 StopSignal: p.StopSignal, 178 } 179 } 180 } 181 182 var buildMethod types.BuildMethod 183 switch b.GetBuildMethod() { 184 case pb.BuildImageOptions_SCM: 185 buildMethod = types.BuildFromSCM 186 case pb.BuildImageOptions_RAW: 187 buildMethod = types.BuildFromRaw 188 case pb.BuildImageOptions_EXIST: 189 buildMethod = types.BuildFromExist 190 } 191 192 return &types.BuildOptions{ 193 Name: b.Name, 194 User: b.User, 195 UID: int(b.Uid), 196 Tags: b.Tags, 197 BuildMethod: buildMethod, 198 Builds: builds, 199 Tar: bytes.NewReader(b.Tar), 200 ExistID: b.GetExistId(), 201 Platform: b.Platform, 202 }, nil 203 } 204 205 func toCoreReplaceOptions(r *pb.ReplaceOptions) (*types.ReplaceOptions, error) { 206 deployOpts, err := toCoreDeployOptions(r.DeployOpt) 207 if err != nil { 208 return nil, err 209 } 210 211 replaceOpts := &types.ReplaceOptions{ 212 DeployOptions: *deployOpts, 213 NetworkInherit: r.Networkinherit, 214 FilterLabels: r.FilterLabels, 215 Copy: r.Copy, 216 IDs: r.IDs, 217 } 218 219 return replaceOpts, err 220 } 221 222 func toCoreDeployOptions(d *pb.DeployOptions) (*types.DeployOptions, error) { 223 if d == nil { 224 return nil, types.ErrNoDeployOpts 225 } 226 if d.Entrypoint == nil || d.Entrypoint.Name == "" { 227 return nil, types.ErrNoEntryInSpec 228 } 229 230 entrypoint := d.Entrypoint 231 entry := &types.Entrypoint{ 232 Name: entrypoint.Name, 233 Commands: utils.MakeCommandLineArgs(fmt.Sprintf("%s %s", d.Entrypoint.Command, d.ExtraArgs)), 234 Privileged: entrypoint.Privileged, 235 Dir: entrypoint.Dir, 236 Publish: entrypoint.Publish, 237 Restart: entrypoint.Restart, 238 Sysctls: entrypoint.Sysctls, 239 } 240 241 if len(d.Entrypoint.Commands) > 0 { 242 entry.Commands = d.Entrypoint.Commands 243 } 244 245 if entrypoint.Log != nil && entrypoint.Log.Type != "" { 246 entry.Log = &types.LogConfig{} 247 entry.Log.Type = entrypoint.Log.Type 248 entry.Log.Config = entrypoint.Log.Config 249 } 250 251 if entrypoint.Healthcheck != nil { 252 entry.HealthCheck = &types.HealthCheck{} 253 entry.HealthCheck.TCPPorts = entrypoint.Healthcheck.TcpPorts 254 entry.HealthCheck.HTTPPort = entrypoint.Healthcheck.HttpPort 255 entry.HealthCheck.HTTPURL = entrypoint.Healthcheck.Url 256 entry.HealthCheck.HTTPCode = int(entrypoint.Healthcheck.Code) 257 } 258 259 if entrypoint.Hook != nil { 260 entry.Hook = &types.Hook{} 261 entry.Hook.AfterStart = entrypoint.Hook.AfterStart 262 entry.Hook.BeforeStop = entrypoint.Hook.BeforeStop 263 entry.Hook.Force = entrypoint.Hook.Force 264 } 265 266 files := []types.LinuxFile{} 267 for filename, bs := range d.Data { 268 file := types.LinuxFile{ 269 Content: bs, 270 Filename: filename, 271 UID: int(d.Owners[filename].GetUid()), 272 GID: int(d.Owners[filename].GetGid()), 273 Mode: d.Modes[filename].GetMode(), 274 } 275 if file.Mode == 0 && file.UID == 0 && file.GID == 0 { 276 file.Mode = 0755 277 } 278 files = append(files, file) 279 } 280 281 nodeFilter := &types.NodeFilter{ 282 Podname: d.Podname, 283 Includes: d.Nodenames, 284 Labels: d.Nodelabels, 285 } 286 if d.NodeFilter != nil { 287 nodeFilter.Includes = d.NodeFilter.Includes 288 nodeFilter.Excludes = d.NodeFilter.Excludes 289 nodeFilter.Labels = d.NodeFilter.Labels 290 } 291 292 return &types.DeployOptions{ 293 Resources: toCoreResources(d.Resources), 294 Name: d.Name, 295 Entrypoint: entry, 296 Podname: d.Podname, 297 NodeFilter: nodeFilter, 298 Image: d.Image, 299 ExtraArgs: d.ExtraArgs, 300 Count: int(d.Count), 301 Env: d.Env, 302 DNS: d.Dns, 303 ExtraHosts: d.ExtraHosts, 304 Networks: d.Networks, 305 User: d.User, 306 Debug: d.Debug, 307 OpenStdin: d.OpenStdin, 308 Labels: d.Labels, 309 DeployStrategy: d.DeployStrategy.String(), 310 NodesLimit: int(d.NodesLimit), 311 IgnoreHook: d.IgnoreHook, 312 AfterCreate: d.AfterCreate, 313 RawArgs: d.RawArgs, 314 Files: files, 315 IgnorePull: d.IgnorePull, 316 }, nil 317 } 318 319 func toRPCCreateWorkloadMessage(c *types.CreateWorkloadMessage) *pb.CreateWorkloadMessage { 320 if c == nil { 321 return nil 322 } 323 324 msg := &pb.CreateWorkloadMessage{ 325 Podname: c.Podname, 326 Nodename: c.Nodename, 327 Id: c.WorkloadID, 328 Name: c.WorkloadName, 329 Success: c.Error == nil, 330 Publish: utils.EncodePublishInfo(c.Publish), 331 Hook: utils.MergeHookOutputs(c.Hook), 332 Resources: toRPCResources(c.Resources), 333 } 334 if c.Error != nil { 335 msg.Error = c.Error.Error() 336 } 337 return msg 338 } 339 340 func toRPCReplaceWorkloadMessage(r *types.ReplaceWorkloadMessage) *pb.ReplaceWorkloadMessage { 341 msg := &pb.ReplaceWorkloadMessage{ 342 Create: toRPCCreateWorkloadMessage(r.Create), 343 Remove: toRPCRemoveWorkloadMessage(r.Remove), 344 } 345 if r.Error != nil { 346 msg.Error = r.Error.Error() 347 } 348 return msg 349 } 350 351 func toRPCCacheImageMessage(r *types.CacheImageMessage) *pb.CacheImageMessage { 352 return &pb.CacheImageMessage{ 353 Image: r.Image, 354 Success: r.Success, 355 Nodename: r.Nodename, 356 Message: r.Message, 357 } 358 } 359 360 func toRPCRemoveImageMessage(r *types.RemoveImageMessage) *pb.RemoveImageMessage { 361 return &pb.RemoveImageMessage{ 362 Image: r.Image, 363 Success: r.Success, 364 Messages: r.Messages, 365 } 366 } 367 368 func toRPCControlWorkloadMessage(c *types.ControlWorkloadMessage) *pb.ControlWorkloadMessage { 369 r := &pb.ControlWorkloadMessage{ 370 Id: c.WorkloadID, 371 Hook: utils.MergeHookOutputs(c.Hook), 372 } 373 if c.Error != nil { 374 r.Error = c.Error.Error() 375 } 376 return r 377 } 378 379 func toRPCRemoveWorkloadMessage(r *types.RemoveWorkloadMessage) *pb.RemoveWorkloadMessage { 380 if r == nil { 381 return nil 382 } 383 return &pb.RemoveWorkloadMessage{ 384 Id: r.WorkloadID, 385 Success: r.Success, 386 Hook: string(utils.MergeHookOutputs(r.Hook)), 387 } 388 } 389 390 func toRPCDissociateWorkloadMessage(r *types.DissociateWorkloadMessage) *pb.DissociateWorkloadMessage { 391 resp := &pb.DissociateWorkloadMessage{ 392 Id: r.WorkloadID, 393 } 394 if r.Error != nil { 395 resp.Error = r.Error.Error() 396 } 397 return resp 398 } 399 400 func toRPCStdStreamType(stdType types.StdStreamType) pb.StdStreamType { 401 switch stdType { 402 case types.EruError: 403 return pb.StdStreamType_ERUERROR 404 case types.TypeWorkloadID: 405 return pb.StdStreamType_TYPEWORKLOADID 406 case types.Stdout: 407 return pb.StdStreamType_STDOUT 408 default: 409 return pb.StdStreamType_STDERR 410 } 411 } 412 413 func toRPCAttachWorkloadMessage(msg *types.AttachWorkloadMessage) *pb.AttachWorkloadMessage { 414 return &pb.AttachWorkloadMessage{ 415 WorkloadId: msg.WorkloadID, 416 Data: msg.Data, 417 StdStreamType: toRPCStdStreamType(msg.StdStreamType), 418 } 419 } 420 421 func toRPCWorkloadStatus(workloadStatus *types.StatusMeta) *pb.WorkloadStatus { 422 r := &pb.WorkloadStatus{} 423 if workloadStatus != nil { 424 r.Id = workloadStatus.ID 425 r.Healthy = workloadStatus.Healthy 426 r.Running = workloadStatus.Running 427 r.Networks = workloadStatus.Networks 428 r.Extension = workloadStatus.Extension 429 } 430 return r 431 } 432 433 func toRPCWorkloadsStatus(workloadsStatus []*types.StatusMeta) *pb.WorkloadsStatus { 434 ret := &pb.WorkloadsStatus{} 435 r := []*pb.WorkloadStatus{} 436 for _, cs := range workloadsStatus { 437 s := toRPCWorkloadStatus(cs) 438 if s != nil { 439 r = append(r, s) 440 } 441 } 442 ret.Status = r 443 return ret 444 } 445 446 func toRPCWorkloads(ctx context.Context, workloads []*types.Workload, labels map[string]string) *pb.Workloads { 447 ret := &pb.Workloads{} 448 cs := []*pb.Workload{} 449 for _, c := range workloads { 450 pWorkload, err := toRPCWorkload(ctx, c) 451 if err != nil { 452 log.WithFunc("transform.toRPCWorkloads").Error(ctx, err, "trans to pb workload failed") 453 continue 454 } 455 if !utils.LabelsFilter(pWorkload.Labels, labels) { 456 continue 457 } 458 cs = append(cs, pWorkload) 459 } 460 ret.Workloads = cs 461 return ret 462 } 463 464 func toRPCWorkload(ctx context.Context, c *types.Workload) (*pb.Workload, error) { 465 publish := map[string]string{} 466 if c.StatusMeta != nil && len(c.StatusMeta.Networks) != 0 { 467 meta := utils.DecodeMetaInLabel(ctx, c.Labels) 468 publish = utils.EncodePublishInfo( 469 utils.MakePublishInfo(c.StatusMeta.Networks, meta.Publish), 470 ) 471 } 472 473 return &pb.Workload{ 474 Id: c.ID, 475 Podname: c.Podname, 476 Nodename: c.Nodename, 477 Name: c.Name, 478 Privileged: c.Privileged, 479 Publish: publish, 480 Image: c.Image, 481 Labels: c.Labels, 482 Status: toRPCWorkloadStatus(c.StatusMeta), 483 CreateTime: c.CreateTime, 484 Resources: toRPCResources(c.Resources), 485 Env: c.Env, 486 }, nil 487 } 488 489 func toRPCLogStreamMessage(msg *types.LogStreamMessage) *pb.LogStreamMessage { 490 r := &pb.LogStreamMessage{ 491 Id: msg.ID, 492 Data: msg.Data, 493 StdStreamType: toRPCStdStreamType(msg.StdStreamType), 494 } 495 if msg.Error != nil { 496 r.Error = msg.Error.Error() 497 } 498 return r 499 } 500 501 func toCoreExecuteWorkloadOptions(b *pb.ExecuteWorkloadOptions) (opts *types.ExecuteWorkloadOptions, err error) { //nolint 502 return &types.ExecuteWorkloadOptions{ 503 WorkloadID: b.WorkloadId, 504 Commands: b.Commands, 505 Envs: b.Envs, 506 Workdir: b.Workdir, 507 OpenStdin: b.OpenStdin, 508 ReplCmd: b.ReplCmd, 509 }, nil 510 } 511 512 func toRPCCapacityMessage(msg *types.CapacityMessage) *pb.CapacityMessage { 513 if msg == nil { 514 return nil 515 } 516 caps := map[string]int64{} 517 for nodename, capacity := range msg.NodeCapacities { 518 caps[nodename] = int64(capacity) 519 } 520 return &pb.CapacityMessage{ 521 Total: int64(msg.Total), 522 NodeCapacities: caps, 523 } 524 } 525 526 func toCoreCacheImageOptions(opts *pb.CacheImageOptions) *types.ImageOptions { 527 return &types.ImageOptions{ 528 Podname: opts.Podname, 529 Nodenames: opts.Nodenames, 530 Images: opts.Images, 531 } 532 } 533 534 func toCoreRemoveImageOptions(opts *pb.RemoveImageOptions) *types.ImageOptions { 535 return &types.ImageOptions{ 536 Podname: opts.Podname, 537 Nodenames: opts.Nodenames, 538 Images: opts.Images, 539 Prune: opts.Prune, 540 } 541 } 542 543 func toCoreResources(resources map[string][]byte) resourcetypes.Resources { 544 r := resourcetypes.Resources{} 545 for k, v := range resources { 546 rp := resourcetypes.RawParams{} 547 if err := json.Unmarshal(v, &rp); err != nil { 548 log.WithFunc("toCoreResources").Errorf(nil, err, "%v", string(v)) // nolint 549 continue 550 } 551 r[k] = rp 552 } 553 return r 554 } 555 556 func toRPCListImageMessage(msg *types.ListImageMessage) *pb.ListImageMessage { 557 m := &pb.ListImageMessage{ 558 Images: []*pb.ImageItem{}, 559 Nodename: "", 560 Err: "", 561 } 562 if msg == nil { 563 return m 564 } 565 if msg.Error != nil { 566 m.Err = msg.Error.Error() 567 return m 568 } 569 570 m.Nodename = msg.Nodename 571 for _, image := range msg.Images { 572 m.Images = append(m.Images, &pb.ImageItem{ 573 Id: image.ID, 574 Tags: image.Tags, 575 }) 576 } 577 578 return m 579 } 580 581 func toCoreListImageOptions(opts *pb.ListImageOptions) *types.ImageOptions { 582 return &types.ImageOptions{ 583 Podname: opts.Podname, 584 Nodenames: opts.Nodenames, 585 Filter: opts.Filter, 586 } 587 } 588 589 func toSendLargeFileOptions(opts *pb.FileOptions) (*types.SendLargeFileOptions, error) { 590 ret := &types.SendLargeFileOptions{ 591 IDs: opts.Ids, 592 Dst: opts.Dst, 593 Size: opts.Size, 594 Mode: opts.Mode.Mode, 595 UID: int(opts.Owner.Uid), 596 GID: int(opts.Owner.Gid), 597 Chunk: opts.Chunk, 598 } 599 err := ret.Validate() 600 return ret, err 601 } 602 603 func toSendLargeFileChunks(file types.LinuxFile, ids []string) []*types.SendLargeFileOptions { 604 maxChunkSize := types.SendLargeFileChunkSize 605 ret := make([]*types.SendLargeFileOptions, 0) 606 for idx := 0; idx < len(file.Content); idx += maxChunkSize { 607 sendLargeFileOptions := &types.SendLargeFileOptions{ 608 IDs: ids, 609 Dst: file.Filename, 610 Size: int64(len(file.Content)), 611 Mode: file.Mode, 612 UID: file.UID, 613 GID: file.GID, 614 } 615 if idx+maxChunkSize > len(file.Content) { 616 sendLargeFileOptions.Chunk = file.Content[idx:] 617 } else { 618 sendLargeFileOptions.Chunk = file.Content[idx : idx+maxChunkSize] 619 } 620 ret = append(ret, sendLargeFileOptions) 621 } 622 return ret 623 } 624 625 func toCoreRawEngineOptions(d *pb.RawEngineOptions) (*types.RawEngineOptions, error) { 626 ret := &types.RawEngineOptions{ 627 ID: d.Id, 628 Op: d.Op, 629 Params: d.Params, 630 IgnoreLock: d.IgnoreLock, 631 } 632 err := ret.Validate() 633 return ret, err 634 } 635 636 func toRPCRawEngineMessage(c *types.RawEngineMessage) *pb.RawEngineMessage { 637 r := &pb.RawEngineMessage{ 638 Id: c.ID, 639 Data: c.Data, 640 } 641 return r 642 }