Skip to content

Commit

Permalink
Cost modeling first pass (#1661)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeljguarino authored Dec 10, 2024
1 parent 1cde9b6 commit cd09c52
Show file tree
Hide file tree
Showing 63 changed files with 1,808 additions and 21 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ erl_crash.dump
*.ez
watchman-*.tar
/priv/data
/data

Dockerfile*
Makefile
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ yalc.lock

secrets/

data/

# config/pubkey.pem
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ ARG TARGETARCH=amd64
# ENV TERRAFORM_VERSION=v1.9.8

# renovate: datasource=github-releases depName=pluralsh/plural-cli
ENV CLI_VERSION=v0.10.1
ENV CLI_VERSION=v0.10.2

# renovate: datasource=github-tags depName=kubernetes/kubernetes
# ENV KUBECTL_VERSION=v1.31.3
Expand Down Expand Up @@ -101,7 +101,8 @@ RUN echo "deb http://deb.debian.org/debian bullseye-backports main" >/etc/apt/s
sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen && \
addgroup --gid 10001 app && \
adduser --home /home/console --uid 10001 --gid 10001 console && \
chown console:app /opt/app
chown console:app /opt/app && \
mkdir -p /opt/app/data

ARG APP_NAME=console
ARG GIT_COMMIT
Expand Down Expand Up @@ -130,4 +131,4 @@ COPY --from=builder /opt/app/_build/prod/rel/console .

USER console

CMD /opt/app/bin/console start
CMD mkdir -p /tmp/sqlite; /opt/app/bin/console start
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ docker-push-ollama: ## push ollama image
download-deprecations:
curl -L https://raw.githubusercontent.com/FairwindsOps/pluto/refs/heads/master/versions.yaml --output static/versions.yml

download-cost:
curl -L https://raw.githubusercontent.com/opencost/opencost/refs/heads/develop/configs/alibaba.json --output priv/cost/alibaba.json
curl -L https://raw.githubusercontent.com/opencost/opencost/refs/heads/develop/configs/aws.json --output priv/cost/aws.json
curl -L https://raw.githubusercontent.com/opencost/opencost/refs/heads/develop/configs/azure.json --output priv/cost/azure.json
curl -L https://raw.githubusercontent.com/opencost/opencost/refs/heads/develop/configs/gcp.json --output priv/cost/gcp.json
curl -L https://raw.githubusercontent.com/opencost/opencost/refs/heads/develop/configs/oracle.json --output priv/cost/oracle.json

build: ## Build the Docker image
docker build --build-arg GIT_COMMIT=$(GIT_COMMIT) \
--build-arg TARGETARCH=$(TARGETARCH) \
Expand Down Expand Up @@ -72,8 +79,10 @@ deploy: ## deploy artifacts to plural
secrets: ## dir to manage random secret
mkdir secrets

data: ## dir for test sqlite data
mkdir data

testup: secrets ## sets up dependent services for test
testup: secrets data ## sets up dependent services for test
docker compose up -d

testdown: ## tear down test dependencies
Expand Down
148 changes: 148 additions & 0 deletions assets/src/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,35 @@ export type ClusterMetricsSummary = {
nodes?: Maybe<Scalars['Int']['output']>;
};

export type ClusterNamespaceUsage = {
__typename?: 'ClusterNamespaceUsage';
cluster?: Maybe<Cluster>;
cpu?: Maybe<Scalars['Float']['output']>;
cpuCost?: Maybe<Scalars['Int']['output']>;
/** the amount of cpu utilized */
cpuUtil?: Maybe<Scalars['Float']['output']>;
id: Scalars['ID']['output'];
insertedAt?: Maybe<Scalars['DateTime']['output']>;
/** the amount of memory utilized */
memUtil?: Maybe<Scalars['Float']['output']>;
memory?: Maybe<Scalars['Float']['output']>;
memoryCost?: Maybe<Scalars['Int']['output']>;
namespace?: Maybe<Scalars['String']['output']>;
updatedAt?: Maybe<Scalars['DateTime']['output']>;
};

export type ClusterNamespaceUsageConnection = {
__typename?: 'ClusterNamespaceUsageConnection';
edges?: Maybe<Array<Maybe<ClusterNamespaceUsageEdge>>>;
pageInfo: PageInfo;
};

export type ClusterNamespaceUsageEdge = {
__typename?: 'ClusterNamespaceUsageEdge';
cursor?: Maybe<Scalars['String']['output']>;
node?: Maybe<ClusterNamespaceUsage>;
};

export type ClusterNodeMetrics = {
__typename?: 'ClusterNodeMetrics';
cpu?: Maybe<Array<Maybe<MetricResponse>>>;
Expand Down Expand Up @@ -1496,6 +1525,34 @@ export type ClusterRevisionEdge = {
node?: Maybe<ClusterRevision>;
};

export type ClusterScalingRecommendation = {
__typename?: 'ClusterScalingRecommendation';
cluster?: Maybe<Cluster>;
container?: Maybe<Scalars['String']['output']>;
cpuRecommendation?: Maybe<Scalars['Float']['output']>;
cpuRequest?: Maybe<Scalars['Float']['output']>;
id: Scalars['ID']['output'];
insertedAt?: Maybe<Scalars['DateTime']['output']>;
memoryRecommendation?: Maybe<Scalars['Float']['output']>;
memoryRequest?: Maybe<Scalars['Float']['output']>;
name?: Maybe<Scalars['String']['output']>;
namespace?: Maybe<Scalars['String']['output']>;
type?: Maybe<ScalingRecommendationType>;
updatedAt?: Maybe<Scalars['DateTime']['output']>;
};

export type ClusterScalingRecommendationConnection = {
__typename?: 'ClusterScalingRecommendationConnection';
edges?: Maybe<Array<Maybe<ClusterScalingRecommendationEdge>>>;
pageInfo: PageInfo;
};

export type ClusterScalingRecommendationEdge = {
__typename?: 'ClusterScalingRecommendationEdge';
cursor?: Maybe<Scalars['String']['output']>;
node?: Maybe<ClusterScalingRecommendation>;
};

export type ClusterServiceAttributes = {
git: GitRefAttributes;
id: Scalars['ID']['input'];
Expand Down Expand Up @@ -1567,6 +1624,52 @@ export type ClusterUpgradePlan = {
incompatibilities?: Maybe<Scalars['Boolean']['output']>;
};

export type ClusterUsage = {
__typename?: 'ClusterUsage';
cluster?: Maybe<Cluster>;
cpu?: Maybe<Scalars['Float']['output']>;
cpuCost?: Maybe<Scalars['Int']['output']>;
/** the amount of cpu utilized */
cpuUtil?: Maybe<Scalars['Float']['output']>;
id: Scalars['ID']['output'];
insertedAt?: Maybe<Scalars['DateTime']['output']>;
/** the amount of memory utilized */
memUtil?: Maybe<Scalars['Float']['output']>;
memory?: Maybe<Scalars['Float']['output']>;
memoryCost?: Maybe<Scalars['Int']['output']>;
namespaces?: Maybe<ClusterNamespaceUsageConnection>;
recommendations?: Maybe<ClusterScalingRecommendationConnection>;
updatedAt?: Maybe<Scalars['DateTime']['output']>;
};


export type ClusterUsageNamespacesArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};


export type ClusterUsageRecommendationsArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};

export type ClusterUsageConnection = {
__typename?: 'ClusterUsageConnection';
edges?: Maybe<Array<Maybe<ClusterUsageEdge>>>;
pageInfo: PageInfo;
};

export type ClusterUsageEdge = {
__typename?: 'ClusterUsageEdge';
cursor?: Maybe<Scalars['String']['output']>;
node?: Maybe<ClusterUsage>;
};

export type Command = {
__typename?: 'Command';
build?: Maybe<Build>;
Expand Down Expand Up @@ -1910,6 +2013,25 @@ export type CostAnalysis = {
totalCost?: Maybe<Scalars['Float']['output']>;
};

/** Settings for cost management */
export type CostSettings = {
__typename?: 'CostSettings';
enabled?: Maybe<Scalars['Boolean']['output']>;
/** the percentage cushion above baseline usage to give when generation recommendations, default 20% */
recommendationCushion?: Maybe<Scalars['Int']['output']>;
/** the percentage change needed to generate a recommendation, default 30% */
recommendationThreshold?: Maybe<Scalars['Int']['output']>;
};

/** Settings for cost management */
export type CostSettingsAttributes = {
enabled?: InputMaybe<Scalars['Boolean']['input']>;
/** the percentage change needed to generate a recommendation, default 20% */
recommendationCushion?: InputMaybe<Scalars['Int']['input']>;
/** the percentage change needed to generate a recommendation, default 30% */
recommendationThreshold?: InputMaybe<Scalars['Int']['input']>;
};

export type CreatePrConfigAttributes = {
/** a scm connection id to use for pr automations */
connectionId?: InputMaybe<Scalars['ID']['input']>;
Expand Down Expand Up @@ -2139,6 +2261,8 @@ export type DeploymentSettings = {
artifactRepository?: Maybe<GitRepository>;
/** your compliant k8s version */
compliantK8sVsn: Scalars['String']['output'];
/** settings for cost management */
cost?: Maybe<CostSettings>;
/** policy for creation of new objects */
createBindings?: Maybe<Array<Maybe<PolicyBinding>>>;
/** the repo to fetch the deploy operators manifests from */
Expand Down Expand Up @@ -2175,6 +2299,8 @@ export type DeploymentSettingsAttributes = {
/** configuration for LLM provider clients */
ai?: InputMaybe<AiSettingsAttributes>;
artifactRepositoryId?: InputMaybe<Scalars['ID']['input']>;
/** settings for cost management functionality */
cost?: InputMaybe<CostSettingsAttributes>;
createBindings?: InputMaybe<Array<InputMaybe<PolicyBindingAttributes>>>;
deployerRepositoryId?: InputMaybe<Scalars['ID']['input']>;
gitBindings?: InputMaybe<Array<InputMaybe<PolicyBindingAttributes>>>;
Expand Down Expand Up @@ -6555,6 +6681,8 @@ export type RootQueryType = {
clusterStackRuns?: Maybe<StackRunConnection>;
/** gets summary information for all healthy/unhealthy clusters in your fleet */
clusterStatuses?: Maybe<Array<Maybe<ClusterStatusInfo>>>;
clusterUsage?: Maybe<ClusterUsage>;
clusterUsages?: Maybe<ClusterUsageConnection>;
/** a relay connection of all clusters visible to the current user */
clusters?: Maybe<ClusterConnection>;
/** renders a full hierarchy of resources recursively owned by this component (useful for CRD views) */
Expand Down Expand Up @@ -6931,6 +7059,19 @@ export type RootQueryTypeClusterStatusesArgs = {
};


export type RootQueryTypeClusterUsageArgs = {
id: Scalars['ID']['input'];
};


export type RootQueryTypeClusterUsagesArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};


export type RootQueryTypeClustersArgs = {
after?: InputMaybe<Scalars['String']['input']>;
backups?: InputMaybe<Scalars['Boolean']['input']>;
Expand Down Expand Up @@ -8031,6 +8172,13 @@ export type S3StoreAttributes = {
secretAccessKey: Scalars['String']['input'];
};

export enum ScalingRecommendationType {
Daemonset = 'DAEMONSET',
Deployment = 'DEPLOYMENT',
Rollout = 'ROLLOUT',
Statefulset = 'STATEFULSET'
}

/** an object representing the means to connect to SCM apis */
export type ScmConnection = {
__typename?: 'ScmConnection';
Expand Down
4 changes: 4 additions & 0 deletions assets/src/routes/consoleRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export const consoleRoutes: RouteObject[] = [
index: true,
element: <Home />,
},
{
path: 'home',
element: <Home />,
},
...secretsRoutes,
...prRoutes,
]
1 change: 1 addition & 0 deletions config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ config :console, Console.Cron.Scheduler,
{"@daily", {Console.Cron.Jobs, :prune_alerts, []}},
{"@daily", {Console.AI.Cron, :trim, []}},
{"@daily", {Console.AI.Cron, :trim_threads, []}},
{"@daily", {Console.Cost.Loader, :load, []}},
{"0 0 * * 0", {Console.AI.Cron, :chats, []}}
]

Expand Down
4 changes: 4 additions & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ config :console, Console.Repo,
queue_target: 1000,
pool: Ecto.Adapters.SQL.Sandbox

config :console, Console.LocalRepo,
adapter: Ecto.Adapters.SQLite3,
database: "data/local.db"

config :console, ConsoleWeb.Endpoint,
http: [port: 4002],
server: false
Expand Down
Loading

0 comments on commit cd09c52

Please sign in to comment.