001/*
002 * VM-Operator
003 * Copyright (C) 2024 Michael N. Lipp
004 * 
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.vmoperator.common;
020
021import com.google.gson.Gson;
022import com.google.gson.JsonObject;
023import com.google.gson.JsonPrimitive;
024import java.util.Collection;
025import java.util.EnumSet;
026import java.util.HashMap;
027import java.util.Map;
028import java.util.Optional;
029import java.util.Set;
030import java.util.function.Function;
031import java.util.stream.Collectors;
032import org.jdrupes.vmoperator.util.GsonPtr;
033
034/**
035 * Represents a VM definition.
036 */
037@SuppressWarnings("PMD.DataClass")
038public class VmDefinitionModel extends K8sDynamicModel {
039
040    /**
041     * The VM state from the VM definition.
042     */
043    public enum RequestedVmState {
044        STOPPED, RUNNING
045    }
046
047    /**
048     * Permissions for accessing and manipulating the VM.
049     */
050    public enum Permission {
051        START("start"), STOP("stop"), RESET("reset"),
052        ACCESS_CONSOLE("accessConsole");
053
054        @SuppressWarnings("PMD.UseConcurrentHashMap")
055        private static Map<String, Permission> reprs = new HashMap<>();
056
057        static {
058            for (var value : EnumSet.allOf(Permission.class)) {
059                reprs.put(value.repr, value);
060            }
061        }
062
063        private final String repr;
064
065        Permission(String repr) {
066            this.repr = repr;
067        }
068
069        /**
070         * Create permission from representation in CRD.
071         *
072         * @param value the value
073         * @return the permission
074         */
075        @SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
076        public static Set<Permission> parse(String value) {
077            if ("*".equals(value)) {
078                return EnumSet.allOf(Permission.class);
079            }
080            return Set.of(reprs.get(value));
081        }
082
083        @Override
084        public String toString() {
085            return repr;
086        }
087    }
088
089    /**
090     * Instantiates a new model from the JSON representation.
091     *
092     * @param delegate the gson instance to use for extracting structured data
093     * @param json the JSON
094     */
095    public VmDefinitionModel(Gson delegate, JsonObject json) {
096        super(delegate, json);
097    }
098
099    /**
100     * Collect all permissions for the given user with the given roles.
101     *
102     * @param user the user
103     * @param roles the roles
104     * @return the sets the
105     */
106    public Set<Permission> permissionsFor(String user,
107            Collection<String> roles) {
108        return GsonPtr.to(data())
109            .getAsListOf(JsonObject.class, "spec", "permissions")
110            .stream().filter(p -> GsonPtr.to(p).getAsString("user")
111                .map(u -> u.equals(user)).orElse(false)
112                || GsonPtr.to(p).getAsString("role").map(roles::contains)
113                    .orElse(false))
114            .map(p -> GsonPtr.to(p).getAsListOf(JsonPrimitive.class, "may")
115                .stream())
116            .flatMap(Function.identity()).map(p -> p.getAsString())
117            .map(Permission::parse).map(Set::stream)
118            .flatMap(Function.identity()).collect(Collectors.toSet());
119    }
120
121    /**
122     * Return the requested VM state
123     *
124     * @return the string
125     */
126    public RequestedVmState vmState() {
127        return GsonPtr.to(data()).getAsString("spec", "vm", "state")
128            .map(s -> "Running".equals(s) ? RequestedVmState.RUNNING
129                : RequestedVmState.STOPPED)
130            .orElse(RequestedVmState.STOPPED);
131    }
132
133    /**
134     * Get the display password serial.
135     *
136     * @return the optional
137     */
138    public Optional<Long> displayPasswordSerial() {
139        return GsonPtr.to(status())
140            .get(JsonPrimitive.class, "displayPasswordSerial")
141            .map(JsonPrimitive::getAsLong);
142    }
143}