Commit 6d3c8119 authored by sonicaj's avatar sonicaj

Test 200 catalog items

parent 66a40e4c

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
* Application liveness / readiness probes were updated addressing a bug where TrueNAS failed
to consider plex application as `Active` if it was configured to only use `HTTPS`.
* Nvidia GPU support was properly added which ensures users having NVIDIA gpu can now consume it
for hardware acceleration.
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
digest: sha256:6ab46f958de11ae6a24d8f7e18417aa9852a8d968d5b0cc94ffa4700449931d6
generated: "2021-02-04T01:15:55.470042+05:00"
apiVersion: v2
appVersion: 1.23.2.4656
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
description: Plex Media Server
home: https://plex.tv/
icon: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
keywords:
- plex
name: plex-1
sources:
- https://hub.docker.com/r/plexinc/pms-docker/
- https://github.com/k8s-at-home/charts/tree/master/charts/plex
upstream_version: 2.1.0
version: 1.6.0
# Plex Media Server helm chart
## Configuration
Please refer to questions.yaml for a detailed overview on supported configurable items.
# Plex
Plex chart is a chart designed to deploy plex in a TrueNAS SCALE kubernetes cluster.
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.20.2.3402-0fec14d92
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: Recreate
plexServiceTCP:
port: 32400
hostNetwork: false
proxy:
# This allows to set a proxy environment variable, which PMS uses to fetch the token and assets like movie cover
enabled: false
# http: "http://proxy:8080"
# https: "https://proxy:8080"
# noproxy: "localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/12"
gpuConfiguration: {}
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
#!/usr/bin/python3
import json
import os
import sys
def migrate(values):
values.update({
'appVolumeMounts': {
'transcode': {
'hostPathEnabled': values['transcodeHostPathEnabled'],
**({'hostPath': values['transcodeHostPath']} if values.get('transcodeHostPath') else {})
},
'config': {
'hostPathEnabled': values['configHostPathEnabled'],
**({'hostPath': values['configHostPath']} if values.get('configHostPath') else {})
},
'data': {
'hostPathEnabled': values['dataHostPathEnabled'],
**({'hostPath': values['dataHostPath']} if values.get('dataHostPath') else {})
},
},
'updateStrategy': values.get('strategyType', 'Recreate'),
})
return values
if __name__ == '__main__':
if len(sys.argv) != 2:
exit(1)
if os.path.exists(sys.argv[1]):
with open(sys.argv[1], 'r') as f:
print(json.dumps(migrate(json.loads(f.read()))))
groups:
- name: "Container Images"
description: "Image to be used for container"
- name: "Container Entrypoint"
description: "Configuration of the executable that will be run when the container is started"
- name: "Container Environment Variables"
description: "Set the environment that will be visible to the container"
- name: "Networking"
description: "Configure networking for container"
- name: "Storage"
description: "Persist and share data that is separate from the lifecycle of the container"
- name: "Plex Configuration"
description: "Configure plex deployment"
- name: "Workload Details"
description: "Configure how workload should be deployed"
- name: "Scaling/Upgrade Policy"
description: "Configure how pods are replaced when configuration is upgraded"
- name: "Restart Policy"
description: "Configure when pod should be restarted in case of failure"
- name: "Resource Reservation"
description: "Specify resources to be allocated to workload"
portals:
web_portal:
protocols:
- "http"
host:
- "$node_ip"
ports:
- "$variable-plexServiceTCP.port"
path: "/web"
questions:
- variable: claimToken
label: "Plex Claim Token"
group: "Plex Configuration"
description: "The claim token for the server to obtain a real server token. If not provided, server is will not be automatically logged in. If server is already logged in, this parameter is ignored. You can obtain a claim token to login your server to your plex account by visiting https://www.plex.tv/claim."
schema:
type: string
default: ""
- variable: hostNetwork
label: "Configure Host Network"
group: "Networking"
schema:
type: boolean
default: false
- variable: environmentVariables
label: "Environment Variables for Plex"
group: "Plex Configuration"
schema:
type: list
default: []
items:
- variable: environmentVariable
label: "Environment Variable"
schema:
type: dict
attrs:
- variable: name
label: "Name"
schema:
type: string
- variable: value
label: "Value"
schema:
type: string
- variable: timezone
label: "Plex container timezone"
group: "Plex Configuration"
schema:
type: string
default: "Etc/UTC"
$ref:
- "definitions/timezone"
# Update strategy
- variable: updateStrategy
description: "Upgrade Policy"
label: "Update Strategy"
group: "Scaling/Upgrade Policy"
schema:
type: string
default: "Recreate"
enum:
- value: "RollingUpdate"
description: "Create new pods and then kill old ones"
- value: "Recreate"
description: "Kill existing pods before creating new ones"
# Port configuration
- variable: plexServiceTCP
label: "Configure Plex TCP Service"
group: "Networking"
schema:
type: dict
attrs:
- variable: port
label: "Port to expose for Plex UI"
schema:
type: int
min: 9000
max: 65535
default: 32400
# Specify GPU configuration
- variable: gpuConfiguration
label: "GPU Configuration"
group: "Resource Reservation"
schema:
type: dict
$ref:
- "definitions/gpuConfiguration"
attrs: []
- variable: appVolumeMounts
label: "Plex Storage"
group: "Storage"
schema:
type: dict
attrs:
- variable: transcode
label: "Transcode Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Transcode Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_transcode"
hidden: true
editable: false
- variable: mountPath
label: "Plex Transcode Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/transcode"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Transcode Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Transcode Volume"
schema:
type: hostpath
required: true
- variable: data
label: "Data Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Data Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_data"
editable: false
hidden: true
- variable: mountPath
label: "Plex Data Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/data"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Data Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Data Volume"
schema:
type: hostpath
required: true
- variable: config
label: "Config Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Config Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_config"
editable: false
hidden: true
- variable: mountPath
label: "Plex Config Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
hidden: true
default: "/config"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Config Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Config Volume"
schema:
type: hostpath
required: true
- variable: shared
label: "Shared Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/shared"
- variable: shared-logs
label: "Shared Logs Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Logs Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/config/Library/Application Support/Plex Media Server/Logs"
1. Get the application URL by running these commands:
http://$node_ip:{{ .Values.plexServiceTCP.port }}/
{{ include "common.deployment.common_config" . | nindent 0 }}
spec: {{ include "common.deployment.common_spec" . | nindent 2 }}
template: {{ include "common.deployment.pod.metadata" . | nindent 4 }}
spec:
{{- if .Values.hostNetwork }}
hostNetwork: {{ .Values.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{ include "common.containers.imageConfig" .Values.image | nindent 10 }}
{{ include "common.containers.gpuConfiguration" .Values | nindent 10 }}
volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }}
- name: plex-probe-check
mountPath: /bin/plex_probe_check.sh
readOnly: true
subPath: entrypoint.sh
ports:
- name: pms
protocol: TCP
containerPort: 32400
{{- if .Values.hostNetwork }}
hostPort: {{ .Values.plexServiceTCP.port }}
{{- end }}
- name: plex-dlna
protocol: TCP
containerPort: 32469
- name: plex-dlna-udp
protocol: UDP
containerPort: 1900
- name: plex-gdm1
protocol: UDP
containerPort: 32410
- name: plex-gdm2
protocol: UDP
containerPort: 32412
- name: plex-gdm3
protocol: UDP
containerPort: 32413
- name: plex-gdm4
protocol: UDP
containerPort: 32414
env:
- name: KUBE_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{ $envList := (default list .Values.environmentVariables) }}
{{ if and .Values.gpuConfiguration (hasKey .Values.gpuConfiguration "nvidia.com/gpu") (gt (get .Values.gpuConfiguration "nvidia.com/gpu" | toDecimal) 0) }}
{{ $envList = mustAppend $envList (dict "name" "NVIDIA_DRIVER_CAPABILITIES" "value" "all") }}
{{ end }}
{{ $envList = mustAppend $envList (dict "name" "TZ" "value" .Values.timezone) }}
{{ $envList = mustAppend $envList (dict "name" "PLEX_CLAIM" "value" .Values.claimToken) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_INTERNAL_ADDRESS" "value" (printf "http://%s:32400" (include "common.names.fullname" .))) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_IMAGE" "value" (printf "%s:%s" .Values.image.repository .Values.image.tag))}}
{{ include "common.containers.environmentVariables" (dict "environmentVariables" $envList) | nindent 12 }}
readinessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
livenessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
startupProbe:
exec:
command:
- /bin/plex_probe_check.sh
initialDelaySeconds: 5
failureThreshold: 40
periodSeconds: 15
volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }}
- name: plex-probe-check
configMap:
defaultMode: 0700
name: "plex-probe-check"
apiVersion: v1
kind: ConfigMap
metadata:
name: "plex-probe-check"
data:
entrypoint.sh: |-
#!/bin/sh
curl -ksf http://$POD_IP:32400/identity -o /dev/null || curl -ksf https://$POD_IP:32400/identity -o /dev/null
{{ $svc := .Values.plexServiceTCP }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "pms" "port" $svc.port "nodePort" $svc.port "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "http" "port" 80 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "https" "port" 443 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna" "port" 1900 "targetPort" "plex-dlna") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "ports" $ports ) }}
{{ if .Values.hostNetwork }}
{{ $_ := set $params.commonService "nameSuffix" "tcp-cluster-ip" }}
{{ $_1 := set $params.commonService "type" "ClusterIP" }}
{{ else }}
{{ $_ := set $params.commonService "nameSuffix" "tcp" }}
{{ $_1 := set $params.commonService "type" "NodePort" }}
{{ end }}
{{ include "common.classes.service" $params }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna-udp" "port" 1900 "protocol" "UDP" "targetPort" "plex-dlna-udp") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm1" "port" 32410 "protocol" "UDP" "targetPort" "plex-gdm1") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm2" "port" 32412 "protocol" "UDP" "targetPort" "plex-gdm2") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm3" "port" 32413 "protocol" "UDP" "targetPort" "plex-gdm3") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm4" "port" 32414 "protocol" "UDP" "targetPort" "plex-gdm4") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "type" "ClusterIP" "ports" $ports "nameSuffix" "udp" ) }}
{{ include "common.classes.service" $params }}
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: "Recreate"
plexServiceTCP:
port: 32400
hostNetwork: false
environmentVariables: []
gpuConfiguration: {}
emptyDirVolumes: true
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
categories:
- entertainment
icon_url: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
* Application liveness / readiness probes were updated addressing a bug where TrueNAS failed
to consider plex application as `Active` if it was configured to only use `HTTPS`.
* Nvidia GPU support was properly added which ensures users having NVIDIA gpu can now consume it
for hardware acceleration.
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
digest: sha256:6ab46f958de11ae6a24d8f7e18417aa9852a8d968d5b0cc94ffa4700449931d6
generated: "2021-02-04T01:15:55.470042+05:00"
apiVersion: v2
appVersion: 1.23.2.4656
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
description: Plex Media Server
home: https://plex.tv/
icon: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
keywords:
- plex
name: plex-10
sources:
- https://hub.docker.com/r/plexinc/pms-docker/
- https://github.com/k8s-at-home/charts/tree/master/charts/plex
upstream_version: 2.1.0
version: 1.6.0
# Plex Media Server helm chart
## Configuration
Please refer to questions.yaml for a detailed overview on supported configurable items.
# Plex
Plex chart is a chart designed to deploy plex in a TrueNAS SCALE kubernetes cluster.
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.20.2.3402-0fec14d92
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: Recreate
plexServiceTCP:
port: 32400
hostNetwork: false
proxy:
# This allows to set a proxy environment variable, which PMS uses to fetch the token and assets like movie cover
enabled: false
# http: "http://proxy:8080"
# https: "https://proxy:8080"
# noproxy: "localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/12"
gpuConfiguration: {}
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
#!/usr/bin/python3
import json
import os
import sys
def migrate(values):
values.update({
'appVolumeMounts': {
'transcode': {
'hostPathEnabled': values['transcodeHostPathEnabled'],
**({'hostPath': values['transcodeHostPath']} if values.get('transcodeHostPath') else {})
},
'config': {
'hostPathEnabled': values['configHostPathEnabled'],
**({'hostPath': values['configHostPath']} if values.get('configHostPath') else {})
},
'data': {
'hostPathEnabled': values['dataHostPathEnabled'],
**({'hostPath': values['dataHostPath']} if values.get('dataHostPath') else {})
},
},
'updateStrategy': values.get('strategyType', 'Recreate'),
})
return values
if __name__ == '__main__':
if len(sys.argv) != 2:
exit(1)
if os.path.exists(sys.argv[1]):
with open(sys.argv[1], 'r') as f:
print(json.dumps(migrate(json.loads(f.read()))))
groups:
- name: "Container Images"
description: "Image to be used for container"
- name: "Container Entrypoint"
description: "Configuration of the executable that will be run when the container is started"
- name: "Container Environment Variables"
description: "Set the environment that will be visible to the container"
- name: "Networking"
description: "Configure networking for container"
- name: "Storage"
description: "Persist and share data that is separate from the lifecycle of the container"
- name: "Plex Configuration"
description: "Configure plex deployment"
- name: "Workload Details"
description: "Configure how workload should be deployed"
- name: "Scaling/Upgrade Policy"
description: "Configure how pods are replaced when configuration is upgraded"
- name: "Restart Policy"
description: "Configure when pod should be restarted in case of failure"
- name: "Resource Reservation"
description: "Specify resources to be allocated to workload"
portals:
web_portal:
protocols:
- "http"
host:
- "$node_ip"
ports:
- "$variable-plexServiceTCP.port"
path: "/web"
questions:
- variable: claimToken
label: "Plex Claim Token"
group: "Plex Configuration"
description: "The claim token for the server to obtain a real server token. If not provided, server is will not be automatically logged in. If server is already logged in, this parameter is ignored. You can obtain a claim token to login your server to your plex account by visiting https://www.plex.tv/claim."
schema:
type: string
default: ""
- variable: hostNetwork
label: "Configure Host Network"
group: "Networking"
schema:
type: boolean
default: false
- variable: environmentVariables
label: "Environment Variables for Plex"
group: "Plex Configuration"
schema:
type: list
default: []
items:
- variable: environmentVariable
label: "Environment Variable"
schema:
type: dict
attrs:
- variable: name
label: "Name"
schema:
type: string
- variable: value
label: "Value"
schema:
type: string
- variable: timezone
label: "Plex container timezone"
group: "Plex Configuration"
schema:
type: string
default: "Etc/UTC"
$ref:
- "definitions/timezone"
# Update strategy
- variable: updateStrategy
description: "Upgrade Policy"
label: "Update Strategy"
group: "Scaling/Upgrade Policy"
schema:
type: string
default: "Recreate"
enum:
- value: "RollingUpdate"
description: "Create new pods and then kill old ones"
- value: "Recreate"
description: "Kill existing pods before creating new ones"
# Port configuration
- variable: plexServiceTCP
label: "Configure Plex TCP Service"
group: "Networking"
schema:
type: dict
attrs:
- variable: port
label: "Port to expose for Plex UI"
schema:
type: int
min: 9000
max: 65535
default: 32400
# Specify GPU configuration
- variable: gpuConfiguration
label: "GPU Configuration"
group: "Resource Reservation"
schema:
type: dict
$ref:
- "definitions/gpuConfiguration"
attrs: []
- variable: appVolumeMounts
label: "Plex Storage"
group: "Storage"
schema:
type: dict
attrs:
- variable: transcode
label: "Transcode Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Transcode Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_transcode"
hidden: true
editable: false
- variable: mountPath
label: "Plex Transcode Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/transcode"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Transcode Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Transcode Volume"
schema:
type: hostpath
required: true
- variable: data
label: "Data Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Data Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_data"
editable: false
hidden: true
- variable: mountPath
label: "Plex Data Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/data"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Data Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Data Volume"
schema:
type: hostpath
required: true
- variable: config
label: "Config Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Config Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_config"
editable: false
hidden: true
- variable: mountPath
label: "Plex Config Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
hidden: true
default: "/config"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Config Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Config Volume"
schema:
type: hostpath
required: true
- variable: shared
label: "Shared Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/shared"
- variable: shared-logs
label: "Shared Logs Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Logs Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/config/Library/Application Support/Plex Media Server/Logs"
1. Get the application URL by running these commands:
http://$node_ip:{{ .Values.plexServiceTCP.port }}/
{{ include "common.deployment.common_config" . | nindent 0 }}
spec: {{ include "common.deployment.common_spec" . | nindent 2 }}
template: {{ include "common.deployment.pod.metadata" . | nindent 4 }}
spec:
{{- if .Values.hostNetwork }}
hostNetwork: {{ .Values.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{ include "common.containers.imageConfig" .Values.image | nindent 10 }}
{{ include "common.containers.gpuConfiguration" .Values | nindent 10 }}
volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }}
- name: plex-probe-check
mountPath: /bin/plex_probe_check.sh
readOnly: true
subPath: entrypoint.sh
ports:
- name: pms
protocol: TCP
containerPort: 32400
{{- if .Values.hostNetwork }}
hostPort: {{ .Values.plexServiceTCP.port }}
{{- end }}
- name: plex-dlna
protocol: TCP
containerPort: 32469
- name: plex-dlna-udp
protocol: UDP
containerPort: 1900
- name: plex-gdm1
protocol: UDP
containerPort: 32410
- name: plex-gdm2
protocol: UDP
containerPort: 32412
- name: plex-gdm3
protocol: UDP
containerPort: 32413
- name: plex-gdm4
protocol: UDP
containerPort: 32414
env:
- name: KUBE_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{ $envList := (default list .Values.environmentVariables) }}
{{ if and .Values.gpuConfiguration (hasKey .Values.gpuConfiguration "nvidia.com/gpu") (gt (get .Values.gpuConfiguration "nvidia.com/gpu" | toDecimal) 0) }}
{{ $envList = mustAppend $envList (dict "name" "NVIDIA_DRIVER_CAPABILITIES" "value" "all") }}
{{ end }}
{{ $envList = mustAppend $envList (dict "name" "TZ" "value" .Values.timezone) }}
{{ $envList = mustAppend $envList (dict "name" "PLEX_CLAIM" "value" .Values.claimToken) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_INTERNAL_ADDRESS" "value" (printf "http://%s:32400" (include "common.names.fullname" .))) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_IMAGE" "value" (printf "%s:%s" .Values.image.repository .Values.image.tag))}}
{{ include "common.containers.environmentVariables" (dict "environmentVariables" $envList) | nindent 12 }}
readinessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
livenessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
startupProbe:
exec:
command:
- /bin/plex_probe_check.sh
initialDelaySeconds: 5
failureThreshold: 40
periodSeconds: 15
volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }}
- name: plex-probe-check
configMap:
defaultMode: 0700
name: "plex-probe-check"
apiVersion: v1
kind: ConfigMap
metadata:
name: "plex-probe-check"
data:
entrypoint.sh: |-
#!/bin/sh
curl -ksf http://$POD_IP:32400/identity -o /dev/null || curl -ksf https://$POD_IP:32400/identity -o /dev/null
{{ $svc := .Values.plexServiceTCP }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "pms" "port" $svc.port "nodePort" $svc.port "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "http" "port" 80 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "https" "port" 443 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna" "port" 1900 "targetPort" "plex-dlna") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "ports" $ports ) }}
{{ if .Values.hostNetwork }}
{{ $_ := set $params.commonService "nameSuffix" "tcp-cluster-ip" }}
{{ $_1 := set $params.commonService "type" "ClusterIP" }}
{{ else }}
{{ $_ := set $params.commonService "nameSuffix" "tcp" }}
{{ $_1 := set $params.commonService "type" "NodePort" }}
{{ end }}
{{ include "common.classes.service" $params }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna-udp" "port" 1900 "protocol" "UDP" "targetPort" "plex-dlna-udp") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm1" "port" 32410 "protocol" "UDP" "targetPort" "plex-gdm1") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm2" "port" 32412 "protocol" "UDP" "targetPort" "plex-gdm2") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm3" "port" 32413 "protocol" "UDP" "targetPort" "plex-gdm3") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm4" "port" 32414 "protocol" "UDP" "targetPort" "plex-gdm4") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "type" "ClusterIP" "ports" $ports "nameSuffix" "udp" ) }}
{{ include "common.classes.service" $params }}
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: "Recreate"
plexServiceTCP:
port: 32400
hostNetwork: false
environmentVariables: []
gpuConfiguration: {}
emptyDirVolumes: true
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
categories:
- entertainment
icon_url: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
* Application liveness / readiness probes were updated addressing a bug where TrueNAS failed
to consider plex application as `Active` if it was configured to only use `HTTPS`.
* Nvidia GPU support was properly added which ensures users having NVIDIA gpu can now consume it
for hardware acceleration.
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
digest: sha256:6ab46f958de11ae6a24d8f7e18417aa9852a8d968d5b0cc94ffa4700449931d6
generated: "2021-02-04T01:15:55.470042+05:00"
apiVersion: v2
appVersion: 1.23.2.4656
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
description: Plex Media Server
home: https://plex.tv/
icon: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
keywords:
- plex
name: plex-11
sources:
- https://hub.docker.com/r/plexinc/pms-docker/
- https://github.com/k8s-at-home/charts/tree/master/charts/plex
upstream_version: 2.1.0
version: 1.6.0
# Plex Media Server helm chart
## Configuration
Please refer to questions.yaml for a detailed overview on supported configurable items.
# Plex
Plex chart is a chart designed to deploy plex in a TrueNAS SCALE kubernetes cluster.
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.20.2.3402-0fec14d92
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: Recreate
plexServiceTCP:
port: 32400
hostNetwork: false
proxy:
# This allows to set a proxy environment variable, which PMS uses to fetch the token and assets like movie cover
enabled: false
# http: "http://proxy:8080"
# https: "https://proxy:8080"
# noproxy: "localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/12"
gpuConfiguration: {}
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
#!/usr/bin/python3
import json
import os
import sys
def migrate(values):
values.update({
'appVolumeMounts': {
'transcode': {
'hostPathEnabled': values['transcodeHostPathEnabled'],
**({'hostPath': values['transcodeHostPath']} if values.get('transcodeHostPath') else {})
},
'config': {
'hostPathEnabled': values['configHostPathEnabled'],
**({'hostPath': values['configHostPath']} if values.get('configHostPath') else {})
},
'data': {
'hostPathEnabled': values['dataHostPathEnabled'],
**({'hostPath': values['dataHostPath']} if values.get('dataHostPath') else {})
},
},
'updateStrategy': values.get('strategyType', 'Recreate'),
})
return values
if __name__ == '__main__':
if len(sys.argv) != 2:
exit(1)
if os.path.exists(sys.argv[1]):
with open(sys.argv[1], 'r') as f:
print(json.dumps(migrate(json.loads(f.read()))))
groups:
- name: "Container Images"
description: "Image to be used for container"
- name: "Container Entrypoint"
description: "Configuration of the executable that will be run when the container is started"
- name: "Container Environment Variables"
description: "Set the environment that will be visible to the container"
- name: "Networking"
description: "Configure networking for container"
- name: "Storage"
description: "Persist and share data that is separate from the lifecycle of the container"
- name: "Plex Configuration"
description: "Configure plex deployment"
- name: "Workload Details"
description: "Configure how workload should be deployed"
- name: "Scaling/Upgrade Policy"
description: "Configure how pods are replaced when configuration is upgraded"
- name: "Restart Policy"
description: "Configure when pod should be restarted in case of failure"
- name: "Resource Reservation"
description: "Specify resources to be allocated to workload"
portals:
web_portal:
protocols:
- "http"
host:
- "$node_ip"
ports:
- "$variable-plexServiceTCP.port"
path: "/web"
questions:
- variable: claimToken
label: "Plex Claim Token"
group: "Plex Configuration"
description: "The claim token for the server to obtain a real server token. If not provided, server is will not be automatically logged in. If server is already logged in, this parameter is ignored. You can obtain a claim token to login your server to your plex account by visiting https://www.plex.tv/claim."
schema:
type: string
default: ""
- variable: hostNetwork
label: "Configure Host Network"
group: "Networking"
schema:
type: boolean
default: false
- variable: environmentVariables
label: "Environment Variables for Plex"
group: "Plex Configuration"
schema:
type: list
default: []
items:
- variable: environmentVariable
label: "Environment Variable"
schema:
type: dict
attrs:
- variable: name
label: "Name"
schema:
type: string
- variable: value
label: "Value"
schema:
type: string
- variable: timezone
label: "Plex container timezone"
group: "Plex Configuration"
schema:
type: string
default: "Etc/UTC"
$ref:
- "definitions/timezone"
# Update strategy
- variable: updateStrategy
description: "Upgrade Policy"
label: "Update Strategy"
group: "Scaling/Upgrade Policy"
schema:
type: string
default: "Recreate"
enum:
- value: "RollingUpdate"
description: "Create new pods and then kill old ones"
- value: "Recreate"
description: "Kill existing pods before creating new ones"
# Port configuration
- variable: plexServiceTCP
label: "Configure Plex TCP Service"
group: "Networking"
schema:
type: dict
attrs:
- variable: port
label: "Port to expose for Plex UI"
schema:
type: int
min: 9000
max: 65535
default: 32400
# Specify GPU configuration
- variable: gpuConfiguration
label: "GPU Configuration"
group: "Resource Reservation"
schema:
type: dict
$ref:
- "definitions/gpuConfiguration"
attrs: []
- variable: appVolumeMounts
label: "Plex Storage"
group: "Storage"
schema:
type: dict
attrs:
- variable: transcode
label: "Transcode Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Transcode Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_transcode"
hidden: true
editable: false
- variable: mountPath
label: "Plex Transcode Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/transcode"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Transcode Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Transcode Volume"
schema:
type: hostpath
required: true
- variable: data
label: "Data Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Data Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_data"
editable: false
hidden: true
- variable: mountPath
label: "Plex Data Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/data"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Data Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Data Volume"
schema:
type: hostpath
required: true
- variable: config
label: "Config Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Config Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_config"
editable: false
hidden: true
- variable: mountPath
label: "Plex Config Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
hidden: true
default: "/config"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Config Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Config Volume"
schema:
type: hostpath
required: true
- variable: shared
label: "Shared Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/shared"
- variable: shared-logs
label: "Shared Logs Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Logs Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/config/Library/Application Support/Plex Media Server/Logs"
1. Get the application URL by running these commands:
http://$node_ip:{{ .Values.plexServiceTCP.port }}/
{{ include "common.deployment.common_config" . | nindent 0 }}
spec: {{ include "common.deployment.common_spec" . | nindent 2 }}
template: {{ include "common.deployment.pod.metadata" . | nindent 4 }}
spec:
{{- if .Values.hostNetwork }}
hostNetwork: {{ .Values.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{ include "common.containers.imageConfig" .Values.image | nindent 10 }}
{{ include "common.containers.gpuConfiguration" .Values | nindent 10 }}
volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }}
- name: plex-probe-check
mountPath: /bin/plex_probe_check.sh
readOnly: true
subPath: entrypoint.sh
ports:
- name: pms
protocol: TCP
containerPort: 32400
{{- if .Values.hostNetwork }}
hostPort: {{ .Values.plexServiceTCP.port }}
{{- end }}
- name: plex-dlna
protocol: TCP
containerPort: 32469
- name: plex-dlna-udp
protocol: UDP
containerPort: 1900
- name: plex-gdm1
protocol: UDP
containerPort: 32410
- name: plex-gdm2
protocol: UDP
containerPort: 32412
- name: plex-gdm3
protocol: UDP
containerPort: 32413
- name: plex-gdm4
protocol: UDP
containerPort: 32414
env:
- name: KUBE_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{ $envList := (default list .Values.environmentVariables) }}
{{ if and .Values.gpuConfiguration (hasKey .Values.gpuConfiguration "nvidia.com/gpu") (gt (get .Values.gpuConfiguration "nvidia.com/gpu" | toDecimal) 0) }}
{{ $envList = mustAppend $envList (dict "name" "NVIDIA_DRIVER_CAPABILITIES" "value" "all") }}
{{ end }}
{{ $envList = mustAppend $envList (dict "name" "TZ" "value" .Values.timezone) }}
{{ $envList = mustAppend $envList (dict "name" "PLEX_CLAIM" "value" .Values.claimToken) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_INTERNAL_ADDRESS" "value" (printf "http://%s:32400" (include "common.names.fullname" .))) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_IMAGE" "value" (printf "%s:%s" .Values.image.repository .Values.image.tag))}}
{{ include "common.containers.environmentVariables" (dict "environmentVariables" $envList) | nindent 12 }}
readinessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
livenessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
startupProbe:
exec:
command:
- /bin/plex_probe_check.sh
initialDelaySeconds: 5
failureThreshold: 40
periodSeconds: 15
volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }}
- name: plex-probe-check
configMap:
defaultMode: 0700
name: "plex-probe-check"
apiVersion: v1
kind: ConfigMap
metadata:
name: "plex-probe-check"
data:
entrypoint.sh: |-
#!/bin/sh
curl -ksf http://$POD_IP:32400/identity -o /dev/null || curl -ksf https://$POD_IP:32400/identity -o /dev/null
{{ $svc := .Values.plexServiceTCP }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "pms" "port" $svc.port "nodePort" $svc.port "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "http" "port" 80 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "https" "port" 443 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna" "port" 1900 "targetPort" "plex-dlna") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "ports" $ports ) }}
{{ if .Values.hostNetwork }}
{{ $_ := set $params.commonService "nameSuffix" "tcp-cluster-ip" }}
{{ $_1 := set $params.commonService "type" "ClusterIP" }}
{{ else }}
{{ $_ := set $params.commonService "nameSuffix" "tcp" }}
{{ $_1 := set $params.commonService "type" "NodePort" }}
{{ end }}
{{ include "common.classes.service" $params }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna-udp" "port" 1900 "protocol" "UDP" "targetPort" "plex-dlna-udp") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm1" "port" 32410 "protocol" "UDP" "targetPort" "plex-gdm1") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm2" "port" 32412 "protocol" "UDP" "targetPort" "plex-gdm2") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm3" "port" 32413 "protocol" "UDP" "targetPort" "plex-gdm3") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm4" "port" 32414 "protocol" "UDP" "targetPort" "plex-gdm4") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "type" "ClusterIP" "ports" $ports "nameSuffix" "udp" ) }}
{{ include "common.classes.service" $params }}
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: "Recreate"
plexServiceTCP:
port: 32400
hostNetwork: false
environmentVariables: []
gpuConfiguration: {}
emptyDirVolumes: true
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
categories:
- entertainment
icon_url: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
* Application liveness / readiness probes were updated addressing a bug where TrueNAS failed
to consider plex application as `Active` if it was configured to only use `HTTPS`.
* Nvidia GPU support was properly added which ensures users having NVIDIA gpu can now consume it
for hardware acceleration.
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
digest: sha256:6ab46f958de11ae6a24d8f7e18417aa9852a8d968d5b0cc94ffa4700449931d6
generated: "2021-02-04T01:15:55.470042+05:00"
apiVersion: v2
appVersion: 1.23.2.4656
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
description: Plex Media Server
home: https://plex.tv/
icon: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
keywords:
- plex
name: plex-12
sources:
- https://hub.docker.com/r/plexinc/pms-docker/
- https://github.com/k8s-at-home/charts/tree/master/charts/plex
upstream_version: 2.1.0
version: 1.6.0
# Plex Media Server helm chart
## Configuration
Please refer to questions.yaml for a detailed overview on supported configurable items.
# Plex
Plex chart is a chart designed to deploy plex in a TrueNAS SCALE kubernetes cluster.
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.20.2.3402-0fec14d92
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: Recreate
plexServiceTCP:
port: 32400
hostNetwork: false
proxy:
# This allows to set a proxy environment variable, which PMS uses to fetch the token and assets like movie cover
enabled: false
# http: "http://proxy:8080"
# https: "https://proxy:8080"
# noproxy: "localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/12"
gpuConfiguration: {}
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
#!/usr/bin/python3
import json
import os
import sys
def migrate(values):
values.update({
'appVolumeMounts': {
'transcode': {
'hostPathEnabled': values['transcodeHostPathEnabled'],
**({'hostPath': values['transcodeHostPath']} if values.get('transcodeHostPath') else {})
},
'config': {
'hostPathEnabled': values['configHostPathEnabled'],
**({'hostPath': values['configHostPath']} if values.get('configHostPath') else {})
},
'data': {
'hostPathEnabled': values['dataHostPathEnabled'],
**({'hostPath': values['dataHostPath']} if values.get('dataHostPath') else {})
},
},
'updateStrategy': values.get('strategyType', 'Recreate'),
})
return values
if __name__ == '__main__':
if len(sys.argv) != 2:
exit(1)
if os.path.exists(sys.argv[1]):
with open(sys.argv[1], 'r') as f:
print(json.dumps(migrate(json.loads(f.read()))))
groups:
- name: "Container Images"
description: "Image to be used for container"
- name: "Container Entrypoint"
description: "Configuration of the executable that will be run when the container is started"
- name: "Container Environment Variables"
description: "Set the environment that will be visible to the container"
- name: "Networking"
description: "Configure networking for container"
- name: "Storage"
description: "Persist and share data that is separate from the lifecycle of the container"
- name: "Plex Configuration"
description: "Configure plex deployment"
- name: "Workload Details"
description: "Configure how workload should be deployed"
- name: "Scaling/Upgrade Policy"
description: "Configure how pods are replaced when configuration is upgraded"
- name: "Restart Policy"
description: "Configure when pod should be restarted in case of failure"
- name: "Resource Reservation"
description: "Specify resources to be allocated to workload"
portals:
web_portal:
protocols:
- "http"
host:
- "$node_ip"
ports:
- "$variable-plexServiceTCP.port"
path: "/web"
questions:
- variable: claimToken
label: "Plex Claim Token"
group: "Plex Configuration"
description: "The claim token for the server to obtain a real server token. If not provided, server is will not be automatically logged in. If server is already logged in, this parameter is ignored. You can obtain a claim token to login your server to your plex account by visiting https://www.plex.tv/claim."
schema:
type: string
default: ""
- variable: hostNetwork
label: "Configure Host Network"
group: "Networking"
schema:
type: boolean
default: false
- variable: environmentVariables
label: "Environment Variables for Plex"
group: "Plex Configuration"
schema:
type: list
default: []
items:
- variable: environmentVariable
label: "Environment Variable"
schema:
type: dict
attrs:
- variable: name
label: "Name"
schema:
type: string
- variable: value
label: "Value"
schema:
type: string
- variable: timezone
label: "Plex container timezone"
group: "Plex Configuration"
schema:
type: string
default: "Etc/UTC"
$ref:
- "definitions/timezone"
# Update strategy
- variable: updateStrategy
description: "Upgrade Policy"
label: "Update Strategy"
group: "Scaling/Upgrade Policy"
schema:
type: string
default: "Recreate"
enum:
- value: "RollingUpdate"
description: "Create new pods and then kill old ones"
- value: "Recreate"
description: "Kill existing pods before creating new ones"
# Port configuration
- variable: plexServiceTCP
label: "Configure Plex TCP Service"
group: "Networking"
schema:
type: dict
attrs:
- variable: port
label: "Port to expose for Plex UI"
schema:
type: int
min: 9000
max: 65535
default: 32400
# Specify GPU configuration
- variable: gpuConfiguration
label: "GPU Configuration"
group: "Resource Reservation"
schema:
type: dict
$ref:
- "definitions/gpuConfiguration"
attrs: []
- variable: appVolumeMounts
label: "Plex Storage"
group: "Storage"
schema:
type: dict
attrs:
- variable: transcode
label: "Transcode Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Transcode Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_transcode"
hidden: true
editable: false
- variable: mountPath
label: "Plex Transcode Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/transcode"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Transcode Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Transcode Volume"
schema:
type: hostpath
required: true
- variable: data
label: "Data Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Data Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_data"
editable: false
hidden: true
- variable: mountPath
label: "Plex Data Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/data"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Data Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Data Volume"
schema:
type: hostpath
required: true
- variable: config
label: "Config Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Config Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_config"
editable: false
hidden: true
- variable: mountPath
label: "Plex Config Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
hidden: true
default: "/config"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Config Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Config Volume"
schema:
type: hostpath
required: true
- variable: shared
label: "Shared Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/shared"
- variable: shared-logs
label: "Shared Logs Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Logs Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/config/Library/Application Support/Plex Media Server/Logs"
1. Get the application URL by running these commands:
http://$node_ip:{{ .Values.plexServiceTCP.port }}/
{{ include "common.deployment.common_config" . | nindent 0 }}
spec: {{ include "common.deployment.common_spec" . | nindent 2 }}
template: {{ include "common.deployment.pod.metadata" . | nindent 4 }}
spec:
{{- if .Values.hostNetwork }}
hostNetwork: {{ .Values.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{ include "common.containers.imageConfig" .Values.image | nindent 10 }}
{{ include "common.containers.gpuConfiguration" .Values | nindent 10 }}
volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }}
- name: plex-probe-check
mountPath: /bin/plex_probe_check.sh
readOnly: true
subPath: entrypoint.sh
ports:
- name: pms
protocol: TCP
containerPort: 32400
{{- if .Values.hostNetwork }}
hostPort: {{ .Values.plexServiceTCP.port }}
{{- end }}
- name: plex-dlna
protocol: TCP
containerPort: 32469
- name: plex-dlna-udp
protocol: UDP
containerPort: 1900
- name: plex-gdm1
protocol: UDP
containerPort: 32410
- name: plex-gdm2
protocol: UDP
containerPort: 32412
- name: plex-gdm3
protocol: UDP
containerPort: 32413
- name: plex-gdm4
protocol: UDP
containerPort: 32414
env:
- name: KUBE_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{ $envList := (default list .Values.environmentVariables) }}
{{ if and .Values.gpuConfiguration (hasKey .Values.gpuConfiguration "nvidia.com/gpu") (gt (get .Values.gpuConfiguration "nvidia.com/gpu" | toDecimal) 0) }}
{{ $envList = mustAppend $envList (dict "name" "NVIDIA_DRIVER_CAPABILITIES" "value" "all") }}
{{ end }}
{{ $envList = mustAppend $envList (dict "name" "TZ" "value" .Values.timezone) }}
{{ $envList = mustAppend $envList (dict "name" "PLEX_CLAIM" "value" .Values.claimToken) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_INTERNAL_ADDRESS" "value" (printf "http://%s:32400" (include "common.names.fullname" .))) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_IMAGE" "value" (printf "%s:%s" .Values.image.repository .Values.image.tag))}}
{{ include "common.containers.environmentVariables" (dict "environmentVariables" $envList) | nindent 12 }}
readinessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
livenessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
startupProbe:
exec:
command:
- /bin/plex_probe_check.sh
initialDelaySeconds: 5
failureThreshold: 40
periodSeconds: 15
volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }}
- name: plex-probe-check
configMap:
defaultMode: 0700
name: "plex-probe-check"
apiVersion: v1
kind: ConfigMap
metadata:
name: "plex-probe-check"
data:
entrypoint.sh: |-
#!/bin/sh
curl -ksf http://$POD_IP:32400/identity -o /dev/null || curl -ksf https://$POD_IP:32400/identity -o /dev/null
{{ $svc := .Values.plexServiceTCP }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "pms" "port" $svc.port "nodePort" $svc.port "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "http" "port" 80 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "https" "port" 443 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna" "port" 1900 "targetPort" "plex-dlna") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "ports" $ports ) }}
{{ if .Values.hostNetwork }}
{{ $_ := set $params.commonService "nameSuffix" "tcp-cluster-ip" }}
{{ $_1 := set $params.commonService "type" "ClusterIP" }}
{{ else }}
{{ $_ := set $params.commonService "nameSuffix" "tcp" }}
{{ $_1 := set $params.commonService "type" "NodePort" }}
{{ end }}
{{ include "common.classes.service" $params }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna-udp" "port" 1900 "protocol" "UDP" "targetPort" "plex-dlna-udp") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm1" "port" 32410 "protocol" "UDP" "targetPort" "plex-gdm1") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm2" "port" 32412 "protocol" "UDP" "targetPort" "plex-gdm2") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm3" "port" 32413 "protocol" "UDP" "targetPort" "plex-gdm3") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm4" "port" 32414 "protocol" "UDP" "targetPort" "plex-gdm4") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "type" "ClusterIP" "ports" $ports "nameSuffix" "udp" ) }}
{{ include "common.classes.service" $params }}
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: "Recreate"
plexServiceTCP:
port: 32400
hostNetwork: false
environmentVariables: []
gpuConfiguration: {}
emptyDirVolumes: true
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
categories:
- entertainment
icon_url: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
* Application liveness / readiness probes were updated addressing a bug where TrueNAS failed
to consider plex application as `Active` if it was configured to only use `HTTPS`.
* Nvidia GPU support was properly added which ensures users having NVIDIA gpu can now consume it
for hardware acceleration.
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
digest: sha256:6ab46f958de11ae6a24d8f7e18417aa9852a8d968d5b0cc94ffa4700449931d6
generated: "2021-02-04T01:15:55.470042+05:00"
apiVersion: v2
appVersion: 1.23.2.4656
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
description: Plex Media Server
home: https://plex.tv/
icon: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
keywords:
- plex
name: plex-13
sources:
- https://hub.docker.com/r/plexinc/pms-docker/
- https://github.com/k8s-at-home/charts/tree/master/charts/plex
upstream_version: 2.1.0
version: 1.6.0
# Plex Media Server helm chart
## Configuration
Please refer to questions.yaml for a detailed overview on supported configurable items.
# Plex
Plex chart is a chart designed to deploy plex in a TrueNAS SCALE kubernetes cluster.
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.20.2.3402-0fec14d92
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: Recreate
plexServiceTCP:
port: 32400
hostNetwork: false
proxy:
# This allows to set a proxy environment variable, which PMS uses to fetch the token and assets like movie cover
enabled: false
# http: "http://proxy:8080"
# https: "https://proxy:8080"
# noproxy: "localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/12"
gpuConfiguration: {}
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
#!/usr/bin/python3
import json
import os
import sys
def migrate(values):
values.update({
'appVolumeMounts': {
'transcode': {
'hostPathEnabled': values['transcodeHostPathEnabled'],
**({'hostPath': values['transcodeHostPath']} if values.get('transcodeHostPath') else {})
},
'config': {
'hostPathEnabled': values['configHostPathEnabled'],
**({'hostPath': values['configHostPath']} if values.get('configHostPath') else {})
},
'data': {
'hostPathEnabled': values['dataHostPathEnabled'],
**({'hostPath': values['dataHostPath']} if values.get('dataHostPath') else {})
},
},
'updateStrategy': values.get('strategyType', 'Recreate'),
})
return values
if __name__ == '__main__':
if len(sys.argv) != 2:
exit(1)
if os.path.exists(sys.argv[1]):
with open(sys.argv[1], 'r') as f:
print(json.dumps(migrate(json.loads(f.read()))))
groups:
- name: "Container Images"
description: "Image to be used for container"
- name: "Container Entrypoint"
description: "Configuration of the executable that will be run when the container is started"
- name: "Container Environment Variables"
description: "Set the environment that will be visible to the container"
- name: "Networking"
description: "Configure networking for container"
- name: "Storage"
description: "Persist and share data that is separate from the lifecycle of the container"
- name: "Plex Configuration"
description: "Configure plex deployment"
- name: "Workload Details"
description: "Configure how workload should be deployed"
- name: "Scaling/Upgrade Policy"
description: "Configure how pods are replaced when configuration is upgraded"
- name: "Restart Policy"
description: "Configure when pod should be restarted in case of failure"
- name: "Resource Reservation"
description: "Specify resources to be allocated to workload"
portals:
web_portal:
protocols:
- "http"
host:
- "$node_ip"
ports:
- "$variable-plexServiceTCP.port"
path: "/web"
questions:
- variable: claimToken
label: "Plex Claim Token"
group: "Plex Configuration"
description: "The claim token for the server to obtain a real server token. If not provided, server is will not be automatically logged in. If server is already logged in, this parameter is ignored. You can obtain a claim token to login your server to your plex account by visiting https://www.plex.tv/claim."
schema:
type: string
default: ""
- variable: hostNetwork
label: "Configure Host Network"
group: "Networking"
schema:
type: boolean
default: false
- variable: environmentVariables
label: "Environment Variables for Plex"
group: "Plex Configuration"
schema:
type: list
default: []
items:
- variable: environmentVariable
label: "Environment Variable"
schema:
type: dict
attrs:
- variable: name
label: "Name"
schema:
type: string
- variable: value
label: "Value"
schema:
type: string
- variable: timezone
label: "Plex container timezone"
group: "Plex Configuration"
schema:
type: string
default: "Etc/UTC"
$ref:
- "definitions/timezone"
# Update strategy
- variable: updateStrategy
description: "Upgrade Policy"
label: "Update Strategy"
group: "Scaling/Upgrade Policy"
schema:
type: string
default: "Recreate"
enum:
- value: "RollingUpdate"
description: "Create new pods and then kill old ones"
- value: "Recreate"
description: "Kill existing pods before creating new ones"
# Port configuration
- variable: plexServiceTCP
label: "Configure Plex TCP Service"
group: "Networking"
schema:
type: dict
attrs:
- variable: port
label: "Port to expose for Plex UI"
schema:
type: int
min: 9000
max: 65535
default: 32400
# Specify GPU configuration
- variable: gpuConfiguration
label: "GPU Configuration"
group: "Resource Reservation"
schema:
type: dict
$ref:
- "definitions/gpuConfiguration"
attrs: []
- variable: appVolumeMounts
label: "Plex Storage"
group: "Storage"
schema:
type: dict
attrs:
- variable: transcode
label: "Transcode Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Transcode Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_transcode"
hidden: true
editable: false
- variable: mountPath
label: "Plex Transcode Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/transcode"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Transcode Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Transcode Volume"
schema:
type: hostpath
required: true
- variable: data
label: "Data Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Data Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_data"
editable: false
hidden: true
- variable: mountPath
label: "Plex Data Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
hidden: true
editable: false
default: "/data"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Data Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Data Volume"
schema:
type: hostpath
required: true
- variable: config
label: "Config Volume"
schema:
type: dict
attrs:
- variable: datasetName
label: "Plex Config Volume Name"
schema:
type: string
$ref:
- "normalize/ixVolume"
show_if: [["hostPathEnabled", "=", false]]
default: "ix-plex_config"
editable: false
hidden: true
- variable: mountPath
label: "Plex Config Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
hidden: true
default: "/config"
- variable: hostPathEnabled
label: "Enable Host Path for Plex Config Volume"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path for Plex Config Volume"
schema:
type: hostpath
required: true
- variable: shared
label: "Shared Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/shared"
- variable: shared-logs
label: "Shared Logs Volume"
schema:
type: dict
hidden: true
attrs:
- variable: emptyDir
label: "Temporary Volume"
schema:
type: boolean
default: true
editable: false
- variable: mountPath
label: "Plex Shared Logs Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
editable: false
default: "/config/Library/Application Support/Plex Media Server/Logs"
1. Get the application URL by running these commands:
http://$node_ip:{{ .Values.plexServiceTCP.port }}/
{{ include "common.deployment.common_config" . | nindent 0 }}
spec: {{ include "common.deployment.common_spec" . | nindent 2 }}
template: {{ include "common.deployment.pod.metadata" . | nindent 4 }}
spec:
{{- if .Values.hostNetwork }}
hostNetwork: {{ .Values.hostNetwork }}
dnsPolicy: ClusterFirstWithHostNet
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{ include "common.containers.imageConfig" .Values.image | nindent 10 }}
{{ include "common.containers.gpuConfiguration" .Values | nindent 10 }}
volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }}
- name: plex-probe-check
mountPath: /bin/plex_probe_check.sh
readOnly: true
subPath: entrypoint.sh
ports:
- name: pms
protocol: TCP
containerPort: 32400
{{- if .Values.hostNetwork }}
hostPort: {{ .Values.plexServiceTCP.port }}
{{- end }}
- name: plex-dlna
protocol: TCP
containerPort: 32469
- name: plex-dlna-udp
protocol: UDP
containerPort: 1900
- name: plex-gdm1
protocol: UDP
containerPort: 32410
- name: plex-gdm2
protocol: UDP
containerPort: 32412
- name: plex-gdm3
protocol: UDP
containerPort: 32413
- name: plex-gdm4
protocol: UDP
containerPort: 32414
env:
- name: KUBE_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{ $envList := (default list .Values.environmentVariables) }}
{{ if and .Values.gpuConfiguration (hasKey .Values.gpuConfiguration "nvidia.com/gpu") (gt (get .Values.gpuConfiguration "nvidia.com/gpu" | toDecimal) 0) }}
{{ $envList = mustAppend $envList (dict "name" "NVIDIA_DRIVER_CAPABILITIES" "value" "all") }}
{{ end }}
{{ $envList = mustAppend $envList (dict "name" "TZ" "value" .Values.timezone) }}
{{ $envList = mustAppend $envList (dict "name" "PLEX_CLAIM" "value" .Values.claimToken) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_INTERNAL_ADDRESS" "value" (printf "http://%s:32400" (include "common.names.fullname" .))) }}
{{ $envList = mustAppend $envList (dict "name" "PMS_IMAGE" "value" (printf "%s:%s" .Values.image.repository .Values.image.tag))}}
{{ include "common.containers.environmentVariables" (dict "environmentVariables" $envList) | nindent 12 }}
readinessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
livenessProbe:
exec:
command:
- /bin/plex_probe_check.sh
failureThreshold: 5
periodSeconds: 15
startupProbe:
exec:
command:
- /bin/plex_probe_check.sh
initialDelaySeconds: 5
failureThreshold: 40
periodSeconds: 15
volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }}
- name: plex-probe-check
configMap:
defaultMode: 0700
name: "plex-probe-check"
apiVersion: v1
kind: ConfigMap
metadata:
name: "plex-probe-check"
data:
entrypoint.sh: |-
#!/bin/sh
curl -ksf http://$POD_IP:32400/identity -o /dev/null || curl -ksf https://$POD_IP:32400/identity -o /dev/null
{{ $svc := .Values.plexServiceTCP }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "pms" "port" $svc.port "nodePort" $svc.port "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "http" "port" 80 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "https" "port" 443 "targetPort" "pms") }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna" "port" 1900 "targetPort" "plex-dlna") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "ports" $ports ) }}
{{ if .Values.hostNetwork }}
{{ $_ := set $params.commonService "nameSuffix" "tcp-cluster-ip" }}
{{ $_1 := set $params.commonService "type" "ClusterIP" }}
{{ else }}
{{ $_ := set $params.commonService "nameSuffix" "tcp" }}
{{ $_1 := set $params.commonService "type" "NodePort" }}
{{ end }}
{{ include "common.classes.service" $params }}
{{ $ports := list }}
{{ $ports = mustAppend $ports (dict "name" "plex-dlna-udp" "port" 1900 "protocol" "UDP" "targetPort" "plex-dlna-udp") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm1" "port" 32410 "protocol" "UDP" "targetPort" "plex-gdm1") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm2" "port" 32412 "protocol" "UDP" "targetPort" "plex-gdm2") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm3" "port" 32413 "protocol" "UDP" "targetPort" "plex-gdm3") }}
{{ $ports = mustAppend $ports (dict "name" "plex-gdm4" "port" 32414 "protocol" "UDP" "targetPort" "plex-gdm4") }}
{{ $params := . }}
{{ $_ := set $params "commonService" (dict "type" "ClusterIP" "ports" $ports "nameSuffix" "udp" ) }}
{{ include "common.classes.service" $params }}
# Default values
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# The Image to use for PLEX
image:
repository: plexinc/pms-docker
tag: 1.23.2.4656-85f0adf5b
pullPolicy: IfNotPresent
##### START --> Official PLEX container environment variables
# Override this with the plex claim token from plex.tv/claim
claimToken: ""
# Set the timezone of the plex server
timezone: "Etc/UTC"
# add your pod network subnet to the `List of IP addresses and networks that are allowed without auth`
# This will override the manual settings, so only use this if you will not need to change it manually.
# This list will be automatically converted to a command seperated string when passed to the container.
# You would specify this when using helm CLI with --set allowedNetworks="{127.0.0.1,10.54.2.0/24}"
# allowedNetworks:
# - 127.0.0.1
# - 10.54.2.0/24
# Instruct the Plex Media Server Container to Change the Configuration Directory Ownership
# Default is true, you would only need to set this if you want to disable it.
# changeConfigDirOwnership: true
# advertiseIp This variable defines the additional IPs on which the server may be be found.
# For example: http://10.1.1.23:32400.
# This adds to the list where the server advertises that it can be found.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# advertiseIp: "http://10.1.1.23:32400"
# Set The user id of the plex user created inside the container.
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexUid: 1000
# Set The group id of the plex group created inside the container
# See https://hub.docker.com/r/plexinc/pms-docker/ for details
# plexGid: 1000
##### END --> Official PLEX container environment variables
# You can add as many Additional ENV variables here
# The following is the same as --set extraEnv.TMPDIR="/transcode"
# extraEnv:
# TMPDIR: /transcode
# upgrade strategy type (e.g. Recreate or RollingUpdate)
updateStrategy: "Recreate"
plexServiceTCP:
port: 32400
hostNetwork: false
environmentVariables: []
gpuConfiguration: {}
emptyDirVolumes: true
appVolumeMounts:
transcode:
emptyDir: true
mountPath: "/transcode"
data:
emptyDir: true
mountPath: "/data"
config:
emptyDir: true
mountPath: "/config"
shared:
emptyDir: true
mountPath: "shared"
shared-logs:
emptyDir: true
mountPath: "/config/Library/Application Support/Plex Media Server/Logs"
categories:
- entertainment
icon_url: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
* Application liveness / readiness probes were updated addressing a bug where TrueNAS failed
to consider plex application as `Active` if it was configured to only use `HTTPS`.
* Nvidia GPU support was properly added which ensures users having NVIDIA gpu can now consume it
for hardware acceleration.
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
digest: sha256:6ab46f958de11ae6a24d8f7e18417aa9852a8d968d5b0cc94ffa4700449931d6
generated: "2021-02-04T01:15:55.470042+05:00"
apiVersion: v2
appVersion: 1.23.2.4656
dependencies:
- name: common
repository: file://../../../library/common/2101.0.0
version: 2101.0.0
description: Plex Media Server
home: https://plex.tv/
icon: https://www.plex.tv/wp-content/uploads/2018/01/pmp-icon-1.png
keywords:
- plex
name: plex-14
sources:
- https://hub.docker.com/r/plexinc/pms-docker/
- https://github.com/k8s-at-home/charts/tree/master/charts/plex
upstream_version: 2.1.0
version: 1.6.0
# Plex Media Server helm chart
## Configuration
Please refer to questions.yaml for a detailed overview on supported configurable items.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment