func (p portoProfile) applyContainerLimits(ctx context.Context, portoConn porto.API, id string) error { limits, ok := p.Profile["container"] if !ok { apexctx.GetLogger(ctx).WithField("container", id).Info("no container limits") return nil } switch limits := limits.(type) { case map[string]interface{}: log := apexctx.GetLogger(ctx).WithField("container", id) for limit, value := range limits { strvalue := fmt.Sprintf("%s", value) log.Debugf("apply %s %s", limit, strvalue) if err := portoConn.SetProperty(id, limit, strvalue); err != nil { return err } } return nil default: return fmt.Errorf("invalid resources type %T", limits) } }
func newContainer(ctx context.Context, portoConn porto.API, cfg containerConfig, info execInfo) (cnt *container, err error) { apexctx.GetLogger(ctx).WithField("container", cfg.ID).Debugf("exec newContainer() with containerConfig: %s; execInfo: %s;", cfg, info) volumeProperties := map[string]string{ "backend": cfg.VolumeBackend, "layers": cfg.Layer, "private": "cocaine-app", } if err = info.applyVolumeLimits(ctx, cfg.ID, volumeProperties); err != nil { return nil, err } volumePath := filepath.Join(cfg.Root, "volume") if err = os.MkdirAll(volumePath, 0775); err != nil { return nil, err } defer func(err *error) { if *err != nil { apexctx.GetLogger(ctx).WithField("container", cfg.ID).Infof("cleaunup unfinished container footprint due to error %v", *err) portoConn.UnlinkVolume(volumePath, cfg.ID) os.RemoveAll(volumePath) } }(&err) volumeDescription, err := portoConn.CreateVolume(volumePath, volumeProperties) apexctx.GetLogger(ctx).WithField("container", cfg.ID).Debugf("create volume with volumeProperties: %s", volumeProperties) if err != nil { if !isEqualPortoError(err, portorpc.EError_VolumeAlreadyExists) { apexctx.GetLogger(ctx).WithError(err).WithField("container", cfg.ID).Error("unable to create volume") return nil, err } apexctx.GetLogger(ctx).WithField("container", cfg.ID).Info("volume already exists") } else { apexctx.GetLogger(ctx).WithField("container", cfg.ID).Infof("created volume %v", volumeDescription) } if err = portoConn.Create(cfg.ID); err != nil { return nil, err } if cfg.SetImgURI { info.env["image_uri"] = info.portoProfile.Registry() + "/" + info.name } if err = portoConn.SetProperty(cfg.ID, "bind", formatBinds(&info)); err != nil { return nil, err } if err = portoConn.SetProperty(cfg.ID, "command", formatCommand(info.executable, info.args)); err != nil { return nil, err } if err = portoConn.SetProperty(cfg.ID, "env", formatEnv(info.env)); err != nil { return nil, err } if info.ulimits != "" { if err = portoConn.SetProperty(cfg.ID, "ulimit", info.ulimits); err != nil { return nil, err } } if cwd := info.Cwd(); cwd != "" { if err = portoConn.SetProperty(cfg.ID, "cwd", cwd); err != nil { return nil, err } } if err = portoConn.SetProperty(cfg.ID, "net", pickNetwork(string(info.NetworkMode()))); err != nil { return nil, err } if err = portoConn.SetProperty(cfg.ID, "enable_porto", "false"); err != nil { return nil, err } if err = portoConn.SetProperty(cfg.ID, "root", volumePath); err != nil { return nil, err } if err = portoConn.LinkVolume(volumePath, cfg.ID); err != nil { return nil, err } if err = info.portoProfile.applyContainerLimits(ctx, portoConn, cfg.ID); err != nil { return nil, err } cnt = &container{ ctx: ctx, containerID: cfg.ID, rootDir: cfg.Root, volumePath: volumePath, cleanupEnabled: cfg.CleanupEnabled, SetImgURI: cfg.SetImgURI, output: ioutil.Discard, } return cnt, nil }