Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphaelGauthier committed Apr 12, 2023
1 parent 56d82d8 commit 1e0d384
Show file tree
Hide file tree
Showing 13 changed files with 454 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ final case class HeartbeatConfiguration(
)

final case class AgentRunInterval(
overrides: Option[Boolean],
interval: Int, // in minute

overrides: Option[Boolean],
interval: Int, // in minute
startMinute: Int,
startHour: Int,
splaytime: Int
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"type": "application",
"source-directories": [
"sources"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"NoRedInk/elm-json-decode-pipeline": "1.0.0",
"TSFoster/elm-tuple-extra": "2.0.0",
"TSFoster/elm-uuid": "4.1.0",
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/file": "1.0.5",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/random": "1.0.0",
"elm/url": "1.0.0",
"elm-community/dict-extra": "2.4.0",
"elm-community/list-extra": "8.5.1",
"elm-community/maybe-extra": "5.2.1",
"isaacseymour/deprecated-time": "1.0.0",
"mcordova47/elm-natural-ordering": "1.0.5",
"myrho/elm-round": "1.0.4",
"toastal/either": "3.6.3",
"webbhuset/elm-json-decode": "1.1.0"
},
"indirect": {
"TSFoster/elm-bytes-extra": "1.3.0",
"TSFoster/elm-md5": "2.0.1",
"TSFoster/elm-sha1": "2.1.1",
"danfishgold/base64-bytes": "1.1.0",
"elm/bytes": "1.0.8",
"elm/parser": "1.1.0",
"elm/regex": "1.0.0",
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.3",
"kuon/elm-string-normalize": "1.0.2",
"rtfeldman/elm-hex": "1.0.0"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
port module Agentschedule exposing (..)

import Browser
import DataTypes exposing (..)
import Http exposing (..)
import Result
import Init exposing (init)
import View exposing (view)
import ApiCalls exposing (saveChanges)
import JsonEncoder exposing (encodeSchedule)
import Json.Decode exposing (Value)
import ViewUtils exposing (hours, minutes)

-- PORTS / SUBSCRIPTIONS
port saveSchedule : Value -> Cmd msg

subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none

main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}

--
-- update loop --
--
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Ignore ->
( model , Cmd.none)

SaveChanges schedule ->
let
ui = model.ui
newModel = {model | currentSettings = Just schedule}
in
--( newModel , saveChanges model)
( newModel , (saveSchedule (encodeSchedule schedule)))

UpdateSchedule schedule ->
let
checkValue : Int -> List Int -> Int
checkValue val list =
if not (List.member val list) then
Maybe.withDefault 0 (List.head list)
else
val
newSchedule = { schedule
| startHour = checkValue schedule.startHour (hours schedule)
, splayHour = checkValue schedule.splayHour (hours schedule)
, startMinute = checkValue schedule.startMinute (minutes schedule)
, splayMinute = checkValue schedule.splayMinute (minutes schedule)
}
in
({model | selectedSettings = Just newSchedule}, Cmd.none)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module ApiCalls exposing (..)

import DataTypes exposing (..)
import Http exposing (..)
import JsonDecoder exposing (..)
import JsonEncoder exposing (..)
import Url.Builder exposing (QueryParameter)


--
-- This files contains all API calls for the Directive compliance UI
--

getUrl: DataTypes.Model -> List String -> List QueryParameter -> String
getUrl m url p=
Url.Builder.relative (m.contextPath :: "secure" :: "api" :: url) p

saveChanges = ""
{--
getGlobalPolicyMode : Model -> Cmd Msg
getGlobalPolicyMode model =
let
req =
request
{ method = "GET"
, headers = []
, url = getUrl model [ "settings", "global_policy_mode" ] []
, body = emptyBody
, expect = expectJson GetGlobalPolicyModeResult decodeGetPolicyMode
, timeout = Nothing
, tracker = Nothing
}
in
req
--}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module DataTypes exposing (..)

import Http exposing (Error)

--
-- All our data types
--

type alias UI =
{ hasWriteRights : Bool
}

type PolicyMode
= Default
| Audit
| Enforce
| None

type Form
= NodeForm String
| GlobalForm


type alias Schedule =
{ overrides : Maybe Bool
, interval : Int
, startHour : Int
, startMinute : Int
, splayHour : Int
, splayMinute : Int
}

type alias Model =
{ contextPath : String
, globalRun : Maybe Schedule
, currentSettings : Maybe Schedule
, selectedSettings : Maybe Schedule
, ui : UI
}

type Msg
= Ignore
| SaveChanges Schedule
| UpdateSchedule Schedule
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Init exposing (..)

import ApiCalls exposing (..)
import DataTypes exposing (..)

init : { contextPath : String, hasWriteRights : Bool, schedule : Maybe Schedule, globalRun : Maybe Schedule } -> ( Model, Cmd Msg )
init flags =
let
initUi = UI flags.hasWriteRights
initModel = Model flags.contextPath flags.globalRun flags.schedule flags.schedule initUi
listInitActions =
[ --getGlobalPolicyMode initModel
]
in
( initModel
, Cmd.batch listInitActions
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module JsonDecoder exposing (..)

import DataTypes exposing (..)
import Json.Decode exposing (..)
import Json.Decode.Pipeline exposing (..)
import Json.Decode.Field exposing (..)

test = ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module JsonEncoder exposing (..)

import DataTypes exposing (..)
import Json.Encode exposing (..)

encodeSchedule : Schedule -> Value
encodeSchedule schedule =
let
override = case schedule.overrides of
Just o -> o
Nothing -> False
in
object (
[ ( "overrides" , bool override )
, ( "interval" , int schedule.interval )
, ( "startHour" , int schedule.startHour )
, ( "startMinute" , int schedule.startMinute )
, ( "splayHour" , int schedule.splayHour )
, ( "splayMinute" , int schedule.splayMinute )
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
module View exposing (..)

import DataTypes exposing (..)
import Html exposing (..)
import Html.Attributes exposing (id, class, href, type_, attribute, disabled, for, checked, selected, value)
import Html.Events exposing (onClick, onInput)
import Maybe.Extra exposing (isJust)
import Dict
import ViewUtils exposing (..)

view : Model -> Html Msg
view model =
div []
[ if model.ui.hasWriteRights then
div [class "explanation-text"]
[ case model.globalRun of
Just globalRun ->
div[]
[ p[]
[ text "By default, agents on all nodes run following the same frequency defined in the global "
, a [href (model.contextPath ++ "/secure/administration/policyServerManagement#cfagentSchedule")][text "Settings"]
, text "."
]
, p[]
[ text "The current global setting is to run every "
, b[][text (getIntervalValue globalRun.interval)]
, text ", starting at "
, b[][text (format2Digits(globalRun.startHour)), text ":", text (format2Digits(globalRun.startMinute))]
, text ", with a maximum delay after scheduled run time (random interval) of "
, b[][text (format2Digits(globalRun.splayHour)), text ":", text (format2Digits(globalRun.splayMinute))]
, text "."
]
, p[][text "You may override this global setting just for this node below:"]
]
Nothing ->
div[]
[ p[][text "This setting will not be applied to policy server."]
, p[][text "By default, the agent runs on all nodes every 5 minutes."]
, p[][text "This high frequency enables fast response times to apply changes and state assessment for high-precision drift and compliance reports."]
, p[][text "You can modify this run interval below, as well as the \"splay time\" across nodes (a random delay that alters scheduled run time, in order to spread load across nodes)."]
]
, case model.currentSettings of
Just currentSettings ->
let
selectedSettings = case model.selectedSettings of
Just s -> s
Nothing -> currentSettings

overrideMode = case selectedSettings.overrides of
Just o -> o
Nothing -> False

disableForm =
case selectedSettings.overrides of
Just o -> not o
Nothing -> False

intervalOptions = intervals
|> Dict.map (\ik iv -> option[value (String.fromInt ik), selected (selectedSettings.interval == ik)][text iv])
|> Dict.values

hourOptions hour = hours selectedSettings
|> List.map (\h -> option[value (String.fromInt h), selected (hour == h)][text (String.fromInt h)])

minuteOptions min = minutes selectedSettings
|> List.map (\m -> option[value (String.fromInt m), selected (min == m)][text (String.fromInt m)])

selectedStartH = selectedSettings.startHour
selectedSplayH = selectedSettings.splayHour
selectedStartM = selectedSettings.startMinute
selectedSplayM = selectedSettings.splayMinute

overrideCheckbox =
if isJust model.globalRun then
ul []
[ li [class "rudder-form"]
[ div [class "input-group"]
[ label [class "input-group-addon", for "override", onClick (UpdateSchedule {selectedSettings | overrides = Just (not overrideMode)})]
[ input [id "override", checked overrideMode, type_ "checkbox"][]
, label [for "override", class"label-radio"]
[ span [class "ion ion-checkmark-round"][]
]
, span [class "ion ion-checkmark-round check-icon"][]
]
, label [for "override", class "form-control"]
[ text "Override global value"
]
]
]
]
else
text ""
in
form [class "form-horizontal"]
[ div[]
[ overrideCheckbox
, div [class "globalConf"]
[ div [class "form-group"]
[ label [for "runInterval", class "control-label"][text "Run agent every "]
, select [class "form-control input-sm schedule", id "runInterval", disabled disableForm, onInput (\i -> UpdateSchedule {selectedSettings | interval = Maybe.withDefault 0 (String.toInt i)})]
( intervalOptions )
]
, div [class "form-group inline-input-group"]
[ label [class "control-label"][text "First run time"]
, div [class "input-group input-group-sm"]
[ select [class "form-control input-sm", id "startHour", onInput (\h -> UpdateSchedule {selectedSettings | startHour = Maybe.withDefault 0 (String.toInt h)}), disabled (disableForm || List.length (hourOptions selectedStartH) <= 1) ]
(hourOptions selectedStartH)
, span [class "input-group-addon"][text ("Hour" ++ if selectedSettings.startHour > 1 then "s" else "")]
, select [class "pull-left form-control input-sm", id "startMinute", onInput (\m -> UpdateSchedule {selectedSettings | startMinute = Maybe.withDefault 0 (String.toInt m)}), disabled disableForm ]
(minuteOptions selectedStartM)
, span [class "input-group-addon"][text ("Minute" ++ if selectedSettings.startMinute > 1 then "s" else "")]
]
]
, div [class "form-group inline-input-group"]
[ label [class "control-label"][text "Maximum delay"]
, div [class "input-group input-group-sm"]
[ select [class "form-control input-sm", id "splayHour", onInput (\h -> UpdateSchedule {selectedSettings | splayHour = Maybe.withDefault 0 (String.toInt h)}), disabled (disableForm || List.length (hourOptions selectedSplayH) <= 1) ]
(hourOptions selectedSplayH)
, span [class "input-group-addon"][text ("Hour" ++ if selectedSettings.splayHour > 1 then "s" else "")]
, select [class "pull-left form-control input-sm", id "splayMinute", onInput (\m -> UpdateSchedule {selectedSettings | splayMinute = Maybe.withDefault 0 (String.toInt m)}), disabled disableForm ]
(minuteOptions selectedSplayM)
, span [class "input-group-addon"][text ("Minute" ++ if selectedSettings.splayMinute > 1 then "s" else "")]
]
]
]
]
, div [class "form-group"]
[ div [class "pull-left control-label"]
[ button [class "btn btn-success btn-save btn-settings", type_ "button", disabled (model.selectedSettings == model.currentSettings), onClick (SaveChanges selectedSettings)][]
]
]
]
Nothing -> text ""
]
else
text "No rights"
]
Loading

0 comments on commit 1e0d384

Please sign in to comment.