Exemplo n.º 1
0
        private async Task <GameState> LoadState(TopoMojo.Api.Data.Gamespace gamespace, bool preview = false)
        {
            var state = Mapper.Map <GameState>(gamespace);

            state.Markdown = await LoadMarkdown(gamespace.Workspace?.Id)
                             ?? $"# {gamespace.Name}";

            if (!preview && !gamespace.HasStarted)
            {
                state.Markdown = state.Markdown.Split("<!-- cut -->").FirstOrDefault();
            }

            if (gamespace.IsActive)
            {
                state.Vms = (await _pod.Find(gamespace.Id))
                            .Select(vm => new VmState
                {
                    Id          = vm.Id,
                    Name        = vm.Name.Untagged(),
                    IsolationId = vm.Name.Tag(),
                    IsRunning   = (vm.State == VmPowerState.Running),
                    IsVisible   = gamespace.IsTemplateVisible(vm.Name)
                })
                            .Where(s => s.IsVisible)
                            .OrderBy(s => s.Name)
                            .ToArray();
            }

            if (preview || gamespace.HasStarted)
            {
                var spec = JsonSerializer.Deserialize <ChallengeSpec>(gamespace.Challenge, jsonOptions);

                if (spec.Challenge == null)
                {
                    return(state);
                }

                // TODO: get active question set

                // map challenge to safe model
                state.Challenge = MapChallenge(spec, 0);
            }

            return(state);
        }
Exemplo n.º 2
0
        private async Task Deploy(TopoMojo.Api.Data.Gamespace gamespace, bool sudo = false)
        {
            var tasks = new List <Task <Vm> >();

            var spec = JsonSerializer.Deserialize <ChallengeSpec>(gamespace.Challenge ?? "{}", jsonOptions);

            var isoTargets = (spec.Challenge?.Iso?.Targets ?? "")
                             .ToLower()
                             .Split(' ', StringSplitOptions.RemoveEmptyEntries);

            var templates = Mapper.Map <List <ConvergedTemplate> >(
                gamespace.Workspace.Templates
                .Where(t => t.Variant == 0 || (t.Variant - 1) == gamespace.Variant)
                );

            foreach (var template in templates.ToList())
            {
                // normalize name for variant-specific templates
                if (template.Variant > 0 && template.Name.EndsWith($"_v{template.Variant}"))
                {
                    template.Name = template.Name.Substring(0, template.Name.LastIndexOf('_'));
                }

                // apply template macro substitutions
                foreach (var kvp in spec.Transforms)
                {
                    template.Guestinfo = template.Guestinfo?.Replace($"##{kvp.Key}##", kvp.Value);
                    template.Detail    = template.Detail?.Replace($"##{kvp.Key}##", kvp.Value);
                }

                // apply challenge iso
                if (string.IsNullOrEmpty(template.Iso) && isoTargets.Contains(template.Name.ToLower()))
                {
                    template.Iso = $"{spec.Challenge.Iso.File}";
                }

                // expand replicas
                int replicas = template.Replicas < 0
                    ? gamespace.PlayerCount
                    : Math.Min(template.Replicas, _options.ReplicaLimit)
                ;

                if (replicas > 1)
                {
                    for (int i = 1; i < replicas; i++)
                    {
                        var tt = template.Clone <ConvergedTemplate>();

                        tt.Name += $"_{i+1}";

                        templates.Add(tt);
                    }

                    template.Name += "_1";
                }
            }

            foreach (var template in templates)
            {
                tasks.Add(
                    _pod.Deploy(
                        template
                        .ToVirtualTemplate(gamespace.Id)
                        .SetHostAffinity(gamespace.Workspace.HostAffinity),
                        sudo
                        )
                    );
            }

            await Task.WhenAll(tasks.ToArray());

            if (gamespace.Workspace.HostAffinity)
            {
                var vms = tasks.Select(t => t.Result).ToArray();

                await _pod.SetAffinity(gamespace.Id, vms, true);

                foreach (var vm in vms)
                {
                    vm.State = VmPowerState.Running;
                }
            }

            if (gamespace.StartTime.Year <= 1)
            {
                gamespace.StartTime = DateTimeOffset.UtcNow;
                await _store.Update(gamespace);
            }
        }