From 2938a40c48c63430f5ca26a73fd30b3a071f96fc Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Sun, 7 May 2017 10:58:01 +0300 Subject: [PATCH 01/21] Docker improve for avoiding unnecessary demo and system data run --- docker/.env | 5 +++++ docker/docker-compose.yml | 6 ++++-- docker/thingsboard-db-schema.env | 5 ----- 3 files changed, 9 insertions(+), 7 deletions(-) delete mode 100644 docker/thingsboard-db-schema.env diff --git a/docker/.env b/docker/.env index ca7f2b0357..f7cecd9ab6 100644 --- a/docker/.env +++ b/docker/.env @@ -1 +1,6 @@ CASSANDRA_DATA_DIR=/home/docker/cassandra_volume + +# cassandra schema container environment variables +SKIP_SCHEMA_CREATION=false +SKIP_SYSTEM_DATA=true +SKIP_DEMO_DATA=true \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index d19332b8de..c79625ae3c 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -28,8 +28,10 @@ services: entrypoint: ./run_thingsboard.sh thingsboard-db-schema: image: "thingsboard/thingsboard-db-schema:1.2.2" - env_file: - - thingsboard-db-schema.env + environment: + - SKIP_SCHEMA_CREATION=${SKIP_SCHEMA_CREATION} + - SKIP_SYSTEM_DATA=${SKIP_SYSTEM_DATA} + - SKIP_DEMO_DATA=${SKIP_DEMO_DATA} entrypoint: ./install_schema.sh db: image: "cassandra:3.9" diff --git a/docker/thingsboard-db-schema.env b/docker/thingsboard-db-schema.env deleted file mode 100644 index c8d2bd83d8..0000000000 --- a/docker/thingsboard-db-schema.env +++ /dev/null @@ -1,5 +0,0 @@ -#Db schema configuration - -SKIP_SCHEMA_CREATION=false -SKIP_SYSTEM_DATA=false -SKIP_DEMO_DATA=false \ No newline at end of file From cd11bb6c053e2e6a94926ca3b0c9de05cbbd240e Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Sun, 7 May 2017 19:54:50 +0300 Subject: [PATCH 02/21] Kubernetes, ZK --- kubernetes/zookeeper.yaml | 167 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 kubernetes/zookeeper.yaml diff --git a/kubernetes/zookeeper.yaml b/kubernetes/zookeeper.yaml new file mode 100644 index 0000000000..efe8d99c27 --- /dev/null +++ b/kubernetes/zookeeper.yaml @@ -0,0 +1,167 @@ +apiVersion: v1 +kind: Service +metadata: + name: zk-headless + labels: + app: zk-headless +spec: + ports: + - port: 2888 + name: server + - port: 3888 + name: leader-election + clusterIP: None + selector: + app: zk +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: zk-config +data: + ensemble: "zk-0;zk-1;zk-2" + jvm.heap: "2G" + tick: "2000" + init: "10" + sync: "5" + client.cnxns: "60" + snap.retain: "3" + purge.interval: "1" +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: zk-budget +spec: + selector: + matchLabels: + app: zk + minAvailable: 2 +--- +apiVersion: apps/v1beta1 +kind: StatefulSet +metadata: + name: zk +spec: + serviceName: zk-headless + replicas: 3 + template: + metadata: + labels: + app: zk + annotations: + pod.alpha.kubernetes.io/initialized: "true" + scheduler.alpha.kubernetes.io/affinity: > + { + "podAntiAffinity": { + "requiredDuringSchedulingIgnoredDuringExecution": [ + { + "labelSelector": { + "matchExpressions": [ + { + "key": "app", + "operator": "In", + "values": [ "zk-headless" ] + } + ] + }, + "topologyKey": "kubernetes.io/hostname" + } + ] + } + } + spec: + containers: + - name: k8szk + imagePullPolicy: Always + image: gcr.io/google_samples/k8szk:v1 + resources: + requests: + memory: "1Gi" + cpu: "0.5" + ports: + - containerPort: 2181 + name: client + - containerPort: 2888 + name: server + - containerPort: 3888 + name: leader-election + env: + - name : ZK_ENSEMBLE + valueFrom: + configMapKeyRef: + name: zk-config + key: ensemble + - name : ZK_HEAP_SIZE + valueFrom: + configMapKeyRef: + name: zk-config + key: jvm.heap + - name : ZK_TICK_TIME + valueFrom: + configMapKeyRef: + name: zk-config + key: tick + - name : ZK_INIT_LIMIT + valueFrom: + configMapKeyRef: + name: zk-config + key: init + - name : ZK_SYNC_LIMIT + valueFrom: + configMapKeyRef: + name: zk-config + key: tick + - name : ZK_MAX_CLIENT_CNXNS + valueFrom: + configMapKeyRef: + name: zk-config + key: client.cnxns + - name: ZK_SNAP_RETAIN_COUNT + valueFrom: + configMapKeyRef: + name: zk-config + key: snap.retain + - name: ZK_PURGE_INTERVAL + valueFrom: + configMapKeyRef: + name: zk-config + key: purge.interval + - name: ZK_CLIENT_PORT + value: "2181" + - name: ZK_SERVER_PORT + value: "2888" + - name: ZK_ELECTION_PORT + value: "3888" + command: + - sh + - -c + - zkGenConfig.sh && zkServer.sh start-foreground + readinessProbe: + exec: + command: + - "zkOk.sh" + initialDelaySeconds: 15 + timeoutSeconds: 5 + livenessProbe: + exec: + command: + - "zkOk.sh" + initialDelaySeconds: 15 + timeoutSeconds: 5 + volumeMounts: + - name: datadir + mountPath: /var/lib/zookeeper + securityContext: + runAsUser: 1000 + fsGroup: 1000 + volumeClaimTemplates: + - metadata: + name: datadir + annotations: + volume.alpha.kubernetes.io/storage-class: anything + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 20Gi \ No newline at end of file From b39416232d59f24d312ce0fb600b882138a8e228 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Tue, 9 May 2017 16:31:48 +0300 Subject: [PATCH 03/21] TB-58: k8 base scripts --- docker/thingsboard-db-schema.env | 3 +- .../thingsboard-db-schema/build_and_deploy.sh | 10 +- .../thingsboard-db-schema/install_schema.sh | 8 +- docker/thingsboard/build_and_deploy.sh | 8 +- docker/thingsboard/run_thingsboard.sh | 3 + kubernetes/cassandra.yaml | 134 ++++++++++++++++++ kubernetes/thingsboard-schema.yaml | 22 +++ kubernetes/thingsboard.yaml | 105 ++++++++++++++ kubernetes/zookeeper.yaml | 37 ++--- 9 files changed, 296 insertions(+), 34 deletions(-) create mode 100644 kubernetes/cassandra.yaml create mode 100644 kubernetes/thingsboard-schema.yaml create mode 100644 kubernetes/thingsboard.yaml diff --git a/docker/thingsboard-db-schema.env b/docker/thingsboard-db-schema.env index c8d2bd83d8..4b20f39a35 100644 --- a/docker/thingsboard-db-schema.env +++ b/docker/thingsboard-db-schema.env @@ -2,4 +2,5 @@ SKIP_SCHEMA_CREATION=false SKIP_SYSTEM_DATA=false -SKIP_DEMO_DATA=false \ No newline at end of file +SKIP_DEMO_DATA=false +CASSANDRA_URL=db \ No newline at end of file diff --git a/docker/thingsboard-db-schema/build_and_deploy.sh b/docker/thingsboard-db-schema/build_and_deploy.sh index d03413735d..428016c839 100755 --- a/docker/thingsboard-db-schema/build_and_deploy.sh +++ b/docker/thingsboard-db-schema/build_and_deploy.sh @@ -20,9 +20,13 @@ cp ../../dao/src/main/resources/schema.cql schema.cql cp ../../dao/src/main/resources/demo-data.cql demo-data.cql cp ../../dao/src/main/resources/system-data.cql system-data.cql -docker build -t thingsboard/thingsboard-db-schema:1.2.2 -t thingsboard/thingsboard-db-schema:latest . +docker build -t thingsboard/thingsboard-db-schema:k8test . docker login -docker push thingsboard/thingsboard-db-schema:1.2.2 -docker push thingsboard/thingsboard-db-schema:latest \ No newline at end of file +docker push thingsboard/thingsboard-db-schema:k8test + +# cleanup +rm schema.cql +rm demo-data.cql +rm system-data.cql \ No newline at end of file diff --git a/docker/thingsboard-db-schema/install_schema.sh b/docker/thingsboard-db-schema/install_schema.sh index f113b90a69..279711933c 100644 --- a/docker/thingsboard-db-schema/install_schema.sh +++ b/docker/thingsboard-db-schema/install_schema.sh @@ -16,7 +16,7 @@ # -until nmap db -p 9042 | grep "9042/tcp open" +until nmap $CASSANDRA_URL -p 9042 | grep "9042/tcp open" do echo "Wait for Cassandra..." sleep 10 @@ -24,7 +24,7 @@ done if [ "$SKIP_SCHEMA_CREATION" == "false" ]; then echo "Creating 'Thingsboard' keyspace..." - cqlsh db -f /root/schema.cql + cqlsh $CASSANDRA_URL -f /root/schema.cql if [ "$?" -eq 0 ]; then echo "'Thingsboard' keyspace was successfully created!" else @@ -34,7 +34,7 @@ fi if [ "$SKIP_SYSTEM_DATA" == "false" ]; then echo "Adding system data..." - cqlsh db -f /root/system-data.cql + cqlsh $CASSANDRA_URL -f /root/system-data.cql if [ "$?" -eq 0 ]; then echo "System data was successfully added!" else @@ -44,7 +44,7 @@ fi if [ "$SKIP_DEMO_DATA" == "false" ]; then echo "Adding demo data..." - cqlsh db -f /root/demo-data.cql + cqlsh $CASSANDRA_URL -f /root/demo-data.cql if [ "$?" -eq 0 ]; then echo "Demo data was successfully added!" else diff --git a/docker/thingsboard/build_and_deploy.sh b/docker/thingsboard/build_and_deploy.sh index 7c02de571c..d2d1e2cb76 100755 --- a/docker/thingsboard/build_and_deploy.sh +++ b/docker/thingsboard/build_and_deploy.sh @@ -18,9 +18,11 @@ cp ../../application/target/thingsboard.deb thingsboard.deb -docker build -t thingsboard/application:1.2.2 -t thingsboard/application:latest . +docker build -t thingsboard/application:k8test . docker login -docker push thingsboard/application:1.2.2 -docker push thingsboard/application:latest \ No newline at end of file +docker push thingsboard/application:k8test + +# cleanup +rm thingsboard.deb \ No newline at end of file diff --git a/docker/thingsboard/run_thingsboard.sh b/docker/thingsboard/run_thingsboard.sh index 877fed7fec..404cc8df9d 100755 --- a/docker/thingsboard/run_thingsboard.sh +++ b/docker/thingsboard/run_thingsboard.sh @@ -34,6 +34,9 @@ done # Copying env variables into conf files printenv | awk -F "=" '{print "export " $1 "='\''" $2 "'\''"}' >> /usr/share/thingsboard/conf/thingsboard.conf +# Set env variable for RPC address +echo "export RPC_HOST='"$(hostname -f)"'" | tee -a /usr/share/thingsboard/conf/thingsboard.conf + cat /usr/share/thingsboard/conf/thingsboard.conf echo "Starting 'Thingsboard' service..." diff --git a/kubernetes/cassandra.yaml b/kubernetes/cassandra.yaml new file mode 100644 index 0000000000..9333f4d939 --- /dev/null +++ b/kubernetes/cassandra.yaml @@ -0,0 +1,134 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: cassandra + name: cassandra +spec: + clusterIP: None + ports: + - port: 9042 + selector: + app: cassandra +--- +apiVersion: storage.k8s.io/v1beta1 +kind: StorageClass +metadata: + name: regular +provisioner: kubernetes.io/gce-pd +parameters: + type: pd-standard +--- +apiVersion: "apps/v1beta1" +kind: StatefulSet +metadata: + name: cassandra +spec: + serviceName: cassandra + replicas: 3 + template: + metadata: + labels: + app: cassandra + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app" + operator: In + values: + - cassandra + topologyKey: "kubernetes.io/hostname" + containers: + - name: cassandra + image: gcr.io/google-samples/cassandra:v12 + imagePullPolicy: Always + ports: + - containerPort: 7000 + name: intra-node + - containerPort: 7001 + name: tls-intra-node + - containerPort: 7199 + name: jmx + - containerPort: 9042 + name: cql + - containerPort: 9160 + name: thrift + resources: + limits: + cpu: "500m" + memory: 1Gi + requests: + cpu: "500m" + memory: 1Gi + securityContext: + capabilities: + add: + - IPC_LOCK + lifecycle: + preStop: + exec: + command: ["/bin/sh", "-c", "PID=$(pidof java) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done"] + env: + - name: MAX_HEAP_SIZE + value: 512M + - name: HEAP_NEWSIZE + value: 100M + - name: CASSANDRA_SEEDS + value: "cassandra-0.cassandra.default.svc.cluster.local" + - name: CASSANDRA_CLUSTER_NAME + value: "K8Demo" + - name: CASSANDRA_DC + value: "DC1-K8Demo" + - name: CASSANDRA_RACK + value: "Rack1-K8Demo" + - name: CASSANDRA_AUTO_BOOTSTRAP + value: "false" + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + readinessProbe: + exec: + command: + - /bin/bash + - -c + - /ready-probe.sh + initialDelaySeconds: 15 + timeoutSeconds: 5 + # These volume mounts are persistent. They are like inline claims, + # but not exactly because the names need to match exactly one of + # the stateful pod volumes. + volumeMounts: + - name: cassandra-data + mountPath: /cassandra_data + - name: cassandra-commitlog + mountPath: /cassandra_commitlog + # These are converted to volume claims by the controller + # and mounted at the paths mentioned above. + # do not use these in production until ssd GCEPersistentDisk or other ssd pd + volumeClaimTemplates: + - metadata: + name: cassandra-data + annotations: + volume.beta.kubernetes.io/storage-class: regular + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 2Gi + - metadata: + name: cassandra-commitlog + annotations: + volume.beta.kubernetes.io/storage-class: regular + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/kubernetes/thingsboard-schema.yaml b/kubernetes/thingsboard-schema.yaml new file mode 100644 index 0000000000..ca0f8b1759 --- /dev/null +++ b/kubernetes/thingsboard-schema.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: tb-db-schema-deployment +spec: + containers: + - name: tb-db-schema-k8 + image: thingsboard/thingsboard-db-schema:k8test + env: + - name: SKIP_SCHEMA_CREATION + value: "false" + - name: SKIP_SYSTEM_DATA + value: "false" + - name : SKIP_DEMO_DATA + value: "false" + - name : CASSANDRA_URL + value: "cassandra" + command: + - sh + - -c + - ./install_schema.sh + restartPolicy: Never \ No newline at end of file diff --git a/kubernetes/thingsboard.yaml b/kubernetes/thingsboard.yaml new file mode 100644 index 0000000000..dfe84b25fc --- /dev/null +++ b/kubernetes/thingsboard.yaml @@ -0,0 +1,105 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: thingsboard-external + labels: + app: thingsboard-external +spec: + ports: + - port: 8080 + name: ui + - port: 1883 + name: mqtt + - port: 5683 + name: coap + - port: 9001 + name: rpc + selector: + app: thingsboard + type: LoadBalancer +--- +apiVersion: v1 +kind: Service +metadata: + name: thingsboard-headless + labels: + app: thingsboard-headless +spec: + ports: + - port: 8080 + name: ui + - port: 1883 + name: mqtt + - port: 5683 + name: coap + - port: 9001 + name: rpc + selector: + app: thingsboard + clusterIP: None +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: tb-config +data: + zookeeper.enabled: "true" + zookeeper.url: "zk-headless" + cassandra.url: "cassandra:9042" +--- +apiVersion: apps/v1beta1 +kind: StatefulSet +metadata: + name: tb +spec: + serviceName: "thingsboard-headless" + replicas: 2 + template: + metadata: + labels: + app: thingsboard + spec: + terminationGracePeriodSeconds: 10 + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app" + operator: In + values: + - thingsboard-headless + topologyKey: "kubernetes.io/hostname" + containers: + - name: thingsboard + image: thingsboard/application:k8test + ports: + - containerPort: 8080 + name: ui + - containerPort: 1883 + name: mqtt + - containerPort: 5683 + name: coap + - containerPort: 9001 + name: rpc + env: + - name: ZOOKEEPER_ENABLED + valueFrom: + configMapKeyRef: + name: tb-config + key: zookeeper.enabled + - name: ZOOKEEPER_URL + valueFrom: + configMapKeyRef: + name: tb-config + key: zookeeper.url + - name : CASSANDRA_URL + valueFrom: + configMapKeyRef: + name: tb-config + key: cassandra.url + command: + - sh + - -c + - ./run_thingsboard.sh \ No newline at end of file diff --git a/kubernetes/zookeeper.yaml b/kubernetes/zookeeper.yaml index efe8d99c27..7107e07ece 100644 --- a/kubernetes/zookeeper.yaml +++ b/kubernetes/zookeeper.yaml @@ -20,7 +20,7 @@ metadata: name: zk-config data: ensemble: "zk-0;zk-1;zk-2" - jvm.heap: "2G" + jvm.heap: "1G" tick: "2000" init: "10" sync: "5" @@ -51,34 +51,25 @@ spec: app: zk annotations: pod.alpha.kubernetes.io/initialized: "true" - scheduler.alpha.kubernetes.io/affinity: > - { - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [ - { - "labelSelector": { - "matchExpressions": [ - { - "key": "app", - "operator": "In", - "values": [ "zk-headless" ] - } - ] - }, - "topologyKey": "kubernetes.io/hostname" - } - ] - } - } spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app" + operator: In + values: + - zk-headless + topologyKey: "kubernetes.io/hostname" containers: - name: k8szk imagePullPolicy: Always image: gcr.io/google_samples/k8szk:v1 resources: requests: - memory: "1Gi" - cpu: "0.5" + memory: "0.5Gi" + cpu: "0.2" ports: - containerPort: 2181 name: client @@ -164,4 +155,4 @@ spec: accessModes: [ "ReadWriteOnce" ] resources: requests: - storage: 20Gi \ No newline at end of file + storage: 1Gi \ No newline at end of file From 73458484c2f4d54d537c3e195071bd627c165eca Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Tue, 9 May 2017 23:38:42 +0300 Subject: [PATCH 04/21] TB-58: k8 base scripts --- .../cassandra}/cassandra.yaml | 0 .../thingsboard-schema.yaml | 5 +- .../thingsboard}/thingsboard.yaml | 69 +++++--- docker/zookeeper/Dockerfile | 55 +++++++ docker/zookeeper/Makefile | 12 ++ docker/zookeeper/zkGenConfig.sh | 151 ++++++++++++++++++ docker/zookeeper/zkOk.sh | 26 +++ .../zookeeper}/zookeeper.yaml | 10 +- 8 files changed, 299 insertions(+), 29 deletions(-) rename {kubernetes => docker/cassandra}/cassandra.yaml (100%) rename {kubernetes => docker/thingsboard-db-schema}/thingsboard-schema.yaml (80%) rename {kubernetes => docker/thingsboard}/thingsboard.yaml (62%) create mode 100644 docker/zookeeper/Dockerfile create mode 100644 docker/zookeeper/Makefile create mode 100755 docker/zookeeper/zkGenConfig.sh create mode 100755 docker/zookeeper/zkOk.sh rename {kubernetes => docker/zookeeper}/zookeeper.yaml (95%) diff --git a/kubernetes/cassandra.yaml b/docker/cassandra/cassandra.yaml similarity index 100% rename from kubernetes/cassandra.yaml rename to docker/cassandra/cassandra.yaml diff --git a/kubernetes/thingsboard-schema.yaml b/docker/thingsboard-db-schema/thingsboard-schema.yaml similarity index 80% rename from kubernetes/thingsboard-schema.yaml rename to docker/thingsboard-db-schema/thingsboard-schema.yaml index ca0f8b1759..141e1e3d41 100644 --- a/kubernetes/thingsboard-schema.yaml +++ b/docker/thingsboard-db-schema/thingsboard-schema.yaml @@ -1,10 +1,11 @@ apiVersion: v1 kind: Pod metadata: - name: tb-db-schema-deployment + name: tb-db-schema spec: containers: - - name: tb-db-schema-k8 + - name: tb-db-schema + imagePullPolicy: Always image: thingsboard/thingsboard-db-schema:k8test env: - name: SKIP_SCHEMA_CREATION diff --git a/kubernetes/thingsboard.yaml b/docker/thingsboard/thingsboard.yaml similarity index 62% rename from kubernetes/thingsboard.yaml rename to docker/thingsboard/thingsboard.yaml index dfe84b25fc..702a7215f5 100644 --- a/kubernetes/thingsboard.yaml +++ b/docker/thingsboard/thingsboard.yaml @@ -2,43 +2,53 @@ apiVersion: v1 kind: Service metadata: - name: thingsboard-external + name: tb-external-ip labels: - app: thingsboard-external + app: tb-external-ip spec: ports: - port: 8080 - name: ui + name: ui-port - port: 1883 - name: mqtt + name: mqtt-port - port: 5683 - name: coap + name: coap-port - port: 9001 - name: rpc + name: rpc-port selector: - app: thingsboard + app: tb type: LoadBalancer --- apiVersion: v1 kind: Service metadata: - name: thingsboard-headless + name: tb-headless labels: - app: thingsboard-headless + app: tb-headless spec: ports: - port: 8080 - name: ui + name: ui-port - port: 1883 - name: mqtt + name: mqtt-port - port: 5683 - name: coap + name: coap-port - port: 9001 - name: rpc + name: rpc-port selector: - app: thingsboard + app: tb clusterIP: None --- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: tb-budget +spec: + selector: + matchLabels: + app: tb + minAvailable: 2 +--- apiVersion: v1 kind: ConfigMap metadata: @@ -53,12 +63,12 @@ kind: StatefulSet metadata: name: tb spec: - serviceName: "thingsboard-headless" + serviceName: "tb-headless" replicas: 2 template: metadata: labels: - app: thingsboard + app: tb spec: terminationGracePeriodSeconds: 10 affinity: @@ -69,20 +79,21 @@ spec: - key: "app" operator: In values: - - thingsboard-headless + - tb-headless topologyKey: "kubernetes.io/hostname" containers: - - name: thingsboard + - name: tb + imagePullPolicy: Always image: thingsboard/application:k8test ports: - containerPort: 8080 - name: ui + name: ui-port - containerPort: 1883 - name: mqtt + name: mqtt-port - containerPort: 5683 - name: coap + name: coap-port - containerPort: 9001 - name: rpc + name: rpc-port env: - name: ZOOKEEPER_ENABLED valueFrom: @@ -102,4 +113,16 @@ spec: command: - sh - -c - - ./run_thingsboard.sh \ No newline at end of file + - ./run_thingsboard.sh +# readinessProbe: +# httpGet: +# path: /login +# port: ui-port +# initialDelaySeconds: 30 +# periodSeconds: 10 + livenessProbe: + httpGet: + path: /login + port: ui-port + initialDelaySeconds: 30 + periodSeconds: 10 \ No newline at end of file diff --git a/docker/zookeeper/Dockerfile b/docker/zookeeper/Dockerfile new file mode 100644 index 0000000000..7752f93b3a --- /dev/null +++ b/docker/zookeeper/Dockerfile @@ -0,0 +1,55 @@ +FROM ubuntu:16.04 +ENV ZK_USER=zookeeper \ +ZK_DATA_DIR=/var/lib/zookeeper/data \ +ZK_DATA_LOG_DIR=/var/lib/zookeeper/log \ +ZK_LOG_DIR=/var/log/zookeeper \ +JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 + +ARG GPG_KEY=C823E3E5B12AF29C67F81976F5CECB3CB5E9BD2D +ARG ZK_DIST=zookeeper-3.4.9 +RUN set -x \ + && apt-get update \ + && apt-get install -y openjdk-8-jre-headless wget netcat-openbsd \ + && wget -q "http://www.apache.org/dist/zookeeper/$ZK_DIST/$ZK_DIST.tar.gz" \ + && wget -q "http://www.apache.org/dist/zookeeper/$ZK_DIST/$ZK_DIST.tar.gz.asc" \ + && export GNUPGHOME="$(mktemp -d)" \ + && gpg --keyserver ha.pool.sks-keyservers.net --recv-key "$GPG_KEY" \ + && gpg --batch --verify "$ZK_DIST.tar.gz.asc" "$ZK_DIST.tar.gz" \ + && tar -xzf "$ZK_DIST.tar.gz" -C /opt \ + && rm -r "$GNUPGHOME" "$ZK_DIST.tar.gz" "$ZK_DIST.tar.gz.asc" \ + && ln -s /opt/$ZK_DIST /opt/zookeeper \ + && rm -rf /opt/zookeeper/CHANGES.txt \ + /opt/zookeeper/README.txt \ + /opt/zookeeper/NOTICE.txt \ + /opt/zookeeper/CHANGES.txt \ + /opt/zookeeper/README_packaging.txt \ + /opt/zookeeper/build.xml \ + /opt/zookeeper/config \ + /opt/zookeeper/contrib \ + /opt/zookeeper/dist-maven \ + /opt/zookeeper/docs \ + /opt/zookeeper/ivy.xml \ + /opt/zookeeper/ivysettings.xml \ + /opt/zookeeper/recipes \ + /opt/zookeeper/src \ + /opt/zookeeper/$ZK_DIST.jar.asc \ + /opt/zookeeper/$ZK_DIST.jar.md5 \ + /opt/zookeeper/$ZK_DIST.jar.sha1 \ + && apt-get autoremove -y wget \ + && rm -rf /var/lib/apt/lists/* + +#Copy configuration generator script to bin +COPY zkGenConfig.sh zkOk.sh /opt/zookeeper/bin/ + +# Create a user for the zookeeper process and configure file system ownership +# for nessecary directories and symlink the distribution as a user executable +RUN set -x \ + && useradd $ZK_USER \ + && [ `id -u $ZK_USER` -eq 1000 ] \ + && [ `id -g $ZK_USER` -eq 1000 ] \ + && mkdir -p $ZK_DATA_DIR $ZK_DATA_LOG_DIR $ZK_LOG_DIR /usr/share/zookeeper /tmp/zookeeper /usr/etc/ \ + && chown -R "$ZK_USER:$ZK_USER" /opt/$ZK_DIST $ZK_DATA_DIR $ZK_LOG_DIR $ZK_DATA_LOG_DIR /tmp/zookeeper \ + && ln -s /opt/zookeeper/conf/ /usr/etc/zookeeper \ + && ln -s /opt/zookeeper/bin/* /usr/bin \ + && ln -s /opt/zookeeper/$ZK_DIST.jar /usr/share/zookeeper/ \ + && ln -s /opt/zookeeper/lib/* /usr/share/zookeeper diff --git a/docker/zookeeper/Makefile b/docker/zookeeper/Makefile new file mode 100644 index 0000000000..a28937f1d5 --- /dev/null +++ b/docker/zookeeper/Makefile @@ -0,0 +1,12 @@ +VERSION=k8test +PROJECT=thingsboard + +all: build + +build: + docker build --pull -t ${PROJECT}/k8szk:${VERSION} . + +push: build + docker push ${PROJECT}/k8szk:${VERSION} + +.PHONY: all build push diff --git a/docker/zookeeper/zkGenConfig.sh b/docker/zookeeper/zkGenConfig.sh new file mode 100755 index 0000000000..cef42f64f7 --- /dev/null +++ b/docker/zookeeper/zkGenConfig.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +# Copyright 2016 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ZK_USER=${ZK_USER:-"zookeeper"} +ZK_LOG_LEVEL=${ZK_LOG_LEVEL:-"INFO"} +ZK_DATA_DIR=${ZK_DATA_DIR:-"/var/lib/zookeeper/data"} +ZK_DATA_LOG_DIR=${ZK_DATA_LOG_DIR:-"/var/lib/zookeeper/log"} +ZK_LOG_DIR=${ZK_LOG_DIR:-"var/log/zookeeper"} +ZK_CONF_DIR=${ZK_CONF_DIR:-"/opt/zookeeper/conf"} +ZK_CLIENT_PORT=${ZK_CLIENT_PORT:-2181} +ZK_SERVER_PORT=${ZK_SERVER_PORT:-2888} +ZK_ELECTION_PORT=${ZK_ELECTION_PORT:-3888} +ZK_TICK_TIME=${ZK_TICK_TIME:-2000} +ZK_INIT_LIMIT=${ZK_INIT_LIMIT:-10} +ZK_SYNC_LIMIT=${ZK_SYNC_LIMIT:-5} +ZK_HEAP_SIZE=${ZK_HEAP_SIZE:-2G} +ZK_MAX_CLIENT_CNXNS=${ZK_MAX_CLIENT_CNXNS:-60} +ZK_MIN_SESSION_TIMEOUT=${ZK_MIN_SESSION_TIMEOUT:- $((ZK_TICK_TIME*2))} +ZK_MAX_SESSION_TIMEOUT=${ZK_MAX_SESSION_TIMEOUT:- $((ZK_TICK_TIME*20))} +ZK_SNAP_RETAIN_COUNT=${ZK_SNAP_RETAIN_COUNT:-3} +ZK_PURGE_INTERVAL=${ZK_PURGE_INTERVAL:-0} +ID_FILE="$ZK_DATA_DIR/myid" +ZK_CONFIG_FILE="$ZK_CONF_DIR/zoo.cfg" +LOGGER_PROPS_FILE="$ZK_CONF_DIR/log4j.properties" +JAVA_ENV_FILE="$ZK_CONF_DIR/java.env" +HOST=`hostname -s` +DOMAIN=`hostname -d` + +function print_servers() { + for (( i=1; i<=$ZK_REPLICAS; i++ )) + do + echo "server.$i=$NAME-$((i-1)).$DOMAIN:$ZK_SERVER_PORT:$ZK_ELECTION_PORT" + done +} + +function validate_env() { + echo "Validating environment" + if [ -z $ZK_REPLICAS ]; then + echo "ZK_REPLICAS is a mandatory environment variable" + exit 1 + fi + + if [[ $HOST =~ (.*)-([0-9]+)$ ]]; then + NAME=${BASH_REMATCH[1]} + ORD=${BASH_REMATCH[2]} + else + echo "Failed to extract ordinal from hostname $HOST" + exit 1 + fi + MY_ID=$((ORD+1)) + echo "ZK_REPLICAS=$ZK_REPLICAS" + echo "MY_ID=$MY_ID" + echo "ZK_LOG_LEVEL=$ZK_LOG_LEVEL" + echo "ZK_DATA_DIR=$ZK_DATA_DIR" + echo "ZK_DATA_LOG_DIR=$ZK_DATA_LOG_DIR" + echo "ZK_LOG_DIR=$ZK_LOG_DIR" + echo "ZK_CLIENT_PORT=$ZK_CLIENT_PORT" + echo "ZK_SERVER_PORT=$ZK_SERVER_PORT" + echo "ZK_ELECTION_PORT=$ZK_ELECTION_PORT" + echo "ZK_TICK_TIME=$ZK_TICK_TIME" + echo "ZK_INIT_LIMIT=$ZK_INIT_LIMIT" + echo "ZK_SYNC_LIMIT=$ZK_SYNC_LIMIT" + echo "ZK_MAX_CLIENT_CNXNS=$ZK_MAX_CLIENT_CNXNS" + echo "ZK_MIN_SESSION_TIMEOUT=$ZK_MIN_SESSION_TIMEOUT" + echo "ZK_MAX_SESSION_TIMEOUT=$ZK_MAX_SESSION_TIMEOUT" + echo "ZK_HEAP_SIZE=$ZK_HEAP_SIZE" + echo "ZK_SNAP_RETAIN_COUNT=$ZK_SNAP_RETAIN_COUNT" + echo "ZK_PURGE_INTERVAL=$ZK_PURGE_INTERVAL" + echo "ENSEMBLE" + print_servers + echo "Environment validation successful" +} + +function create_config() { + rm -f $ZK_CONFIG_FILE + echo "Creating ZooKeeper configuration" + echo "#This file was autogenerated by k8szk DO NOT EDIT" >> $ZK_CONFIG_FILE + echo "clientPort=$ZK_CLIENT_PORT" >> $ZK_CONFIG_FILE + echo "dataDir=$ZK_DATA_DIR" >> $ZK_CONFIG_FILE + echo "dataLogDir=$ZK_DATA_LOG_DIR" >> $ZK_CONFIG_FILE + echo "tickTime=$ZK_TICK_TIME" >> $ZK_CONFIG_FILE + echo "initLimit=$ZK_INIT_LIMIT" >> $ZK_CONFIG_FILE + echo "syncLimit=$ZK_SYNC_LIMIT" >> $ZK_CONFIG_FILE + echo "maxClientCnxns=$ZK_MAX_CLIENT_CNXNS" >> $ZK_CONFIG_FILE + echo "minSessionTimeout=$ZK_MIN_SESSION_TIMEOUT" >> $ZK_CONFIG_FILE + echo "maxSessionTimeout=$ZK_MAX_SESSION_TIMEOUT" >> $ZK_CONFIG_FILE + echo "autopurge.snapRetainCount=$ZK_SNAP_RETAIN_COUNT" >> $ZK_CONFIG_FILE + echo "autopurge.purgeInteval=$ZK_PURGE_INTERVAL" >> $ZK_CONFIG_FILE + + if [ $ZK_REPLICAS -gt 1 ]; then + print_servers >> $ZK_CONFIG_FILE + fi + echo "Wrote ZooKeeper configuration file to $ZK_CONFIG_FILE" +} + +function create_data_dirs() { + echo "Creating ZooKeeper data directories and setting permissions" + if [ ! -d $ZK_DATA_DIR ]; then + mkdir -p $ZK_DATA_DIR + chown -R $ZK_USER:$ZK_USER $ZK_DATA_DIR + fi + + if [ ! -d $ZK_DATA_LOG_DIR ]; then + mkdir -p $ZK_DATA_LOG_DIR + chown -R $ZK_USER:$ZK_USER $ZK_DATA_LOG_DIR + fi + + if [ ! -d $ZK_LOG_DIR ]; then + mkdir -p $ZK_LOG_DIR + chown -R $ZK_USER:$ZK_USER $ZK_LOG_DIR + fi + if [ ! -f $ID_FILE ]; then + echo $MY_ID >> $ID_FILE + fi + echo "Created ZooKeeper data directories and set permissions in $ZK_DATA_DIR" +} + +function create_log_props () { + rm -f $LOGGER_PROPS_FILE + echo "Creating ZooKeeper log4j configuration" + echo "zookeeper.root.logger=CONSOLE" >> $LOGGER_PROPS_FILE + echo "zookeeper.console.threshold="$ZK_LOG_LEVEL >> $LOGGER_PROPS_FILE + echo "log4j.rootLogger=\${zookeeper.root.logger}" >> $LOGGER_PROPS_FILE + echo "log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender" >> $LOGGER_PROPS_FILE + echo "log4j.appender.CONSOLE.Threshold=\${zookeeper.console.threshold}" >> $LOGGER_PROPS_FILE + echo "log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout" >> $LOGGER_PROPS_FILE + echo "log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n" >> $LOGGER_PROPS_FILE + echo "Wrote log4j configuration to $LOGGER_PROPS_FILE" +} + +function create_java_env() { + rm -f $JAVA_ENV_FILE + echo "Creating JVM configuration file" + echo "ZOO_LOG_DIR=$ZK_LOG_DIR" >> $JAVA_ENV_FILE + echo "JVMFLAGS=\"-Xmx$ZK_HEAP_SIZE -Xms$ZK_HEAP_SIZE\"" >> $JAVA_ENV_FILE + echo "Wrote JVM configuration to $JAVA_ENV_FILE" +} + +validate_env && create_config && create_log_props && create_data_dirs && create_java_env diff --git a/docker/zookeeper/zkOk.sh b/docker/zookeeper/zkOk.sh new file mode 100755 index 0000000000..dbe417682f --- /dev/null +++ b/docker/zookeeper/zkOk.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright 2016 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# zkOk.sh uses the ruok ZooKeeper four letter work to determine if the instance +# is health. The $? variable will be set to 0 if server responds that it is +# healthy, or 1 if the server fails to respond. + +ZK_CLIENT_PORT=${ZK_CLIENT_PORT:-2181} +OK=$(echo ruok | nc 127.0.0.1 $ZK_CLIENT_PORT) +if [ "$OK" == "imok" ]; then + exit 0 +else + exit 1 +fi \ No newline at end of file diff --git a/kubernetes/zookeeper.yaml b/docker/zookeeper/zookeeper.yaml similarity index 95% rename from kubernetes/zookeeper.yaml rename to docker/zookeeper/zookeeper.yaml index 7107e07ece..4184a3ab8e 100644 --- a/kubernetes/zookeeper.yaml +++ b/docker/zookeeper/zookeeper.yaml @@ -20,7 +20,7 @@ metadata: name: zk-config data: ensemble: "zk-0;zk-1;zk-2" - jvm.heap: "1G" + jvm.heap: "500m" tick: "2000" init: "10" sync: "5" @@ -65,11 +65,11 @@ spec: containers: - name: k8szk imagePullPolicy: Always - image: gcr.io/google_samples/k8szk:v1 + image: thingsboard/k8szk:k8test resources: requests: - memory: "0.5Gi" - cpu: "0.2" + memory: "500Mi" + cpu: "250m" ports: - containerPort: 2181 name: client @@ -83,6 +83,8 @@ spec: configMapKeyRef: name: zk-config key: ensemble + - name : ZK_REPLICAS + value: "3" - name : ZK_HEAP_SIZE valueFrom: configMapKeyRef: From 08e9e903f393cbef4c0ff154537bb276579117e6 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Wed, 10 May 2017 21:01:06 +0300 Subject: [PATCH 05/21] TB-58: k8s feature improvements --- docker/cassandra/Dockerfile | 5 ++ docker/cassandra/Makefile | 13 ++++ docker/cassandra/cassandra.yaml | 37 ++++------- .../ready-probe.sh} | 27 ++++---- docker/common/common.yaml | 9 +++ docker/deploy.sh | 31 ---------- docker/deploy_cassandra_zookeeper.sh | 31 ---------- docker/thingsboard-db-schema/Makefile | 13 ++++ .../thingsboard-db-schema/build_and_deploy.sh | 32 ---------- ...schema.yaml => thingsboard-db-schema.yaml} | 4 +- docker/thingsboard/Makefile | 13 ++++ docker/thingsboard/thingsboard.yaml | 35 +++++------ docker/zookeeper/Makefile | 7 ++- docker/zookeeper/zkGenConfig.sh | 2 +- docker/zookeeper/zookeeper.yaml | 62 ++++++++++++------- 15 files changed, 141 insertions(+), 180 deletions(-) create mode 100644 docker/cassandra/Dockerfile create mode 100644 docker/cassandra/Makefile rename docker/{thingsboard/build_and_deploy.sh => cassandra/ready-probe.sh} (69%) create mode 100644 docker/common/common.yaml delete mode 100755 docker/deploy.sh delete mode 100755 docker/deploy_cassandra_zookeeper.sh create mode 100644 docker/thingsboard-db-schema/Makefile delete mode 100755 docker/thingsboard-db-schema/build_and_deploy.sh rename docker/thingsboard-db-schema/{thingsboard-schema.yaml => thingsboard-db-schema.yaml} (77%) create mode 100644 docker/thingsboard/Makefile diff --git a/docker/cassandra/Dockerfile b/docker/cassandra/Dockerfile new file mode 100644 index 0000000000..72084cd0af --- /dev/null +++ b/docker/cassandra/Dockerfile @@ -0,0 +1,5 @@ +FROM cassandra:3.9 + +COPY ready-probe.sh / + +CMD ["cassandra", "-f"] \ No newline at end of file diff --git a/docker/cassandra/Makefile b/docker/cassandra/Makefile new file mode 100644 index 0000000000..ea71c6340c --- /dev/null +++ b/docker/cassandra/Makefile @@ -0,0 +1,13 @@ +VERSION=k8stest +PROJECT=thingsboard +APP=cassandra + +all: build + +build: + docker build --pull -t ${PROJECT}/${APP}:${VERSION} . + +push: build + docker push ${PROJECT}/${APP}:${VERSION} + +.PHONY: all build push \ No newline at end of file diff --git a/docker/cassandra/cassandra.yaml b/docker/cassandra/cassandra.yaml index 9333f4d939..c3772b15e1 100644 --- a/docker/cassandra/cassandra.yaml +++ b/docker/cassandra/cassandra.yaml @@ -1,30 +1,23 @@ apiVersion: v1 kind: Service metadata: + name: cassandra-headless labels: - app: cassandra - name: cassandra + app: cassandra-headless spec: - clusterIP: None ports: - port: 9042 + name: cql + clusterIP: None selector: app: cassandra --- -apiVersion: storage.k8s.io/v1beta1 -kind: StorageClass -metadata: - name: regular -provisioner: kubernetes.io/gce-pd -parameters: - type: pd-standard ---- apiVersion: "apps/v1beta1" kind: StatefulSet metadata: name: cassandra spec: - serviceName: cassandra + serviceName: cassandra-headless replicas: 3 template: metadata: @@ -39,11 +32,11 @@ spec: - key: "app" operator: In values: - - cassandra + - cassandra-headless topologyKey: "kubernetes.io/hostname" containers: - name: cassandra - image: gcr.io/google-samples/cassandra:v12 + image: thingsboard/cassandra:k8stest imagePullPolicy: Always ports: - containerPort: 7000 @@ -77,7 +70,7 @@ spec: - name: HEAP_NEWSIZE value: 100M - name: CASSANDRA_SEEDS - value: "cassandra-0.cassandra.default.svc.cluster.local" + value: "cassandra-0.cassandra-headless.default.svc.cluster.local" - name: CASSANDRA_CLUSTER_NAME value: "K8Demo" - name: CASSANDRA_DC @@ -102,22 +95,16 @@ spec: - /ready-probe.sh initialDelaySeconds: 15 timeoutSeconds: 5 - # These volume mounts are persistent. They are like inline claims, - # but not exactly because the names need to match exactly one of - # the stateful pod volumes. volumeMounts: - name: cassandra-data - mountPath: /cassandra_data + mountPath: /var/lib/cassandra/data - name: cassandra-commitlog - mountPath: /cassandra_commitlog - # These are converted to volume claims by the controller - # and mounted at the paths mentioned above. - # do not use these in production until ssd GCEPersistentDisk or other ssd pd + mountPath: /var/lib/cassandra/commitlog volumeClaimTemplates: - metadata: name: cassandra-data annotations: - volume.beta.kubernetes.io/storage-class: regular + volume.beta.kubernetes.io/storage-class: slow spec: accessModes: [ "ReadWriteOnce" ] resources: @@ -126,7 +113,7 @@ spec: - metadata: name: cassandra-commitlog annotations: - volume.beta.kubernetes.io/storage-class: regular + volume.beta.kubernetes.io/storage-class: slow spec: accessModes: [ "ReadWriteOnce" ] resources: diff --git a/docker/thingsboard/build_and_deploy.sh b/docker/cassandra/ready-probe.sh similarity index 69% rename from docker/thingsboard/build_and_deploy.sh rename to docker/cassandra/ready-probe.sh index d2d1e2cb76..989f4d90a1 100755 --- a/docker/thingsboard/build_and_deploy.sh +++ b/docker/cassandra/ready-probe.sh @@ -1,6 +1,6 @@ #!/bin/bash -# -# Copyright © 2016-2017 The Thingsboard Authors + +# Copyright 2016 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,16 +13,15 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# - - -cp ../../application/target/thingsboard.deb thingsboard.deb - -docker build -t thingsboard/application:k8test . - -docker login - -docker push thingsboard/application:k8test -# cleanup -rm thingsboard.deb \ No newline at end of file +if [[ $(nodetool status | grep $POD_IP) == *"UN"* ]]; then + if [[ $DEBUG ]]; then + echo "UN"; + fi + exit 0; +else + if [[ $DEBUG ]]; then + echo "Not Up"; + fi + exit 1; +fi \ No newline at end of file diff --git a/docker/common/common.yaml b/docker/common/common.yaml new file mode 100644 index 0000000000..610c027911 --- /dev/null +++ b/docker/common/common.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: storage.k8s.io/v1beta1 +kind: StorageClass +metadata: + name: slow +provisioner: kubernetes.io/gce-pd +parameters: + type: pd-standard +--- \ No newline at end of file diff --git a/docker/deploy.sh b/docker/deploy.sh deleted file mode 100755 index ed69f7b0c7..0000000000 --- a/docker/deploy.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2017 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -command='docker-compose -f docker-compose.yml -f docker-compose.random.yml' - -echo "stopping images.." -$command stop - -echo "removing stopped images.." -$command rm -f - -echo "building images.." -$command build - -echo "starting images..." -$command up -d diff --git a/docker/deploy_cassandra_zookeeper.sh b/docker/deploy_cassandra_zookeeper.sh deleted file mode 100755 index a116e2130e..0000000000 --- a/docker/deploy_cassandra_zookeeper.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2017 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -command='docker-compose -f docker-compose.yml -f docker-compose.static.yml' - -echo "stopping images.." -$command stop - -echo "removing stopped images.." -$command rm -f - -echo "building images.." -$command build - -echo "starting cassandra, zookeeper, thingsboard-db-schema images..." -$command up -d db zk thingsboard-db-schema diff --git a/docker/thingsboard-db-schema/Makefile b/docker/thingsboard-db-schema/Makefile new file mode 100644 index 0000000000..653153940f --- /dev/null +++ b/docker/thingsboard-db-schema/Makefile @@ -0,0 +1,13 @@ +VERSION=k8stest +PROJECT=thingsboard +APP=thingsboard-db-schema + +all: build + +build: + docker build --pull -t ${PROJECT}/${APP}:${VERSION} . + +push: build + docker push ${PROJECT}/${APP}:${VERSION} + +.PHONY: all build push \ No newline at end of file diff --git a/docker/thingsboard-db-schema/build_and_deploy.sh b/docker/thingsboard-db-schema/build_and_deploy.sh deleted file mode 100755 index 428016c839..0000000000 --- a/docker/thingsboard-db-schema/build_and_deploy.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2017 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -cp ../../dao/src/main/resources/schema.cql schema.cql -cp ../../dao/src/main/resources/demo-data.cql demo-data.cql -cp ../../dao/src/main/resources/system-data.cql system-data.cql - -docker build -t thingsboard/thingsboard-db-schema:k8test . - -docker login - -docker push thingsboard/thingsboard-db-schema:k8test - -# cleanup -rm schema.cql -rm demo-data.cql -rm system-data.cql \ No newline at end of file diff --git a/docker/thingsboard-db-schema/thingsboard-schema.yaml b/docker/thingsboard-db-schema/thingsboard-db-schema.yaml similarity index 77% rename from docker/thingsboard-db-schema/thingsboard-schema.yaml rename to docker/thingsboard-db-schema/thingsboard-db-schema.yaml index 141e1e3d41..dbc4f587f2 100644 --- a/docker/thingsboard-db-schema/thingsboard-schema.yaml +++ b/docker/thingsboard-db-schema/thingsboard-db-schema.yaml @@ -6,7 +6,7 @@ spec: containers: - name: tb-db-schema imagePullPolicy: Always - image: thingsboard/thingsboard-db-schema:k8test + image: thingsboard/thingsboard-db-schema:k8stest env: - name: SKIP_SCHEMA_CREATION value: "false" @@ -15,7 +15,7 @@ spec: - name : SKIP_DEMO_DATA value: "false" - name : CASSANDRA_URL - value: "cassandra" + value: "cassandra-headless" command: - sh - -c diff --git a/docker/thingsboard/Makefile b/docker/thingsboard/Makefile new file mode 100644 index 0000000000..29203e30d3 --- /dev/null +++ b/docker/thingsboard/Makefile @@ -0,0 +1,13 @@ +VERSION=k8stest +PROJECT=thingsboard +APP=application + +all: build + +build: + docker build --pull -t ${PROJECT}/${APP}:${VERSION} . + +push: build + docker push ${PROJECT}/${APP}:${VERSION} + +.PHONY: all build push \ No newline at end of file diff --git a/docker/thingsboard/thingsboard.yaml b/docker/thingsboard/thingsboard.yaml index 702a7215f5..a9c1df37d8 100644 --- a/docker/thingsboard/thingsboard.yaml +++ b/docker/thingsboard/thingsboard.yaml @@ -8,13 +8,11 @@ metadata: spec: ports: - port: 8080 - name: ui-port + name: ui - port: 1883 - name: mqtt-port + name: mqtt - port: 5683 - name: coap-port - - port: 9001 - name: rpc-port + name: coap selector: app: tb type: LoadBalancer @@ -27,14 +25,8 @@ metadata: app: tb-headless spec: ports: - - port: 8080 - name: ui-port - - port: 1883 - name: mqtt-port - - port: 5683 - name: coap-port - port: 9001 - name: rpc-port + name: rpc selector: app: tb clusterIP: None @@ -56,7 +48,7 @@ metadata: data: zookeeper.enabled: "true" zookeeper.url: "zk-headless" - cassandra.url: "cassandra:9042" + cassandra.url: "cassandra-headless:9042" --- apiVersion: apps/v1beta1 kind: StatefulSet @@ -84,16 +76,23 @@ spec: containers: - name: tb imagePullPolicy: Always - image: thingsboard/application:k8test + image: thingsboard/application:k8stest ports: - containerPort: 8080 - name: ui-port + name: ui - containerPort: 1883 - name: mqtt-port + name: mqtt - containerPort: 5683 - name: coap-port + name: coap - containerPort: 9001 - name: rpc-port + name: rpc + resources: + limits: + cpu: "250m" + memory: "500Mi" + requests: + cpu: "250m" + memory: "500Mi" env: - name: ZOOKEEPER_ENABLED valueFrom: diff --git a/docker/zookeeper/Makefile b/docker/zookeeper/Makefile index a28937f1d5..4c7a8c4007 100644 --- a/docker/zookeeper/Makefile +++ b/docker/zookeeper/Makefile @@ -1,12 +1,13 @@ -VERSION=k8test +VERSION=k8stest PROJECT=thingsboard +APP=zk all: build build: - docker build --pull -t ${PROJECT}/k8szk:${VERSION} . + docker build --pull -t ${PROJECT}/${APP}:${VERSION} . push: build - docker push ${PROJECT}/k8szk:${VERSION} + docker push ${PROJECT}/${APP}:${VERSION} .PHONY: all build push diff --git a/docker/zookeeper/zkGenConfig.sh b/docker/zookeeper/zkGenConfig.sh index cef42f64f7..0b3365bcac 100755 --- a/docker/zookeeper/zkGenConfig.sh +++ b/docker/zookeeper/zkGenConfig.sh @@ -86,7 +86,7 @@ function validate_env() { function create_config() { rm -f $ZK_CONFIG_FILE echo "Creating ZooKeeper configuration" - echo "#This file was autogenerated by k8szk DO NOT EDIT" >> $ZK_CONFIG_FILE + echo "#This file was autogenerated by zk DO NOT EDIT" >> $ZK_CONFIG_FILE echo "clientPort=$ZK_CLIENT_PORT" >> $ZK_CONFIG_FILE echo "dataDir=$ZK_DATA_DIR" >> $ZK_CONFIG_FILE echo "dataLogDir=$ZK_DATA_LOG_DIR" >> $ZK_CONFIG_FILE diff --git a/docker/zookeeper/zookeeper.yaml b/docker/zookeeper/zookeeper.yaml index 4184a3ab8e..00bca9c902 100644 --- a/docker/zookeeper/zookeeper.yaml +++ b/docker/zookeeper/zookeeper.yaml @@ -20,6 +20,7 @@ metadata: name: zk-config data: ensemble: "zk-0;zk-1;zk-2" + replicas: "3" jvm.heap: "500m" tick: "2000" init: "10" @@ -27,6 +28,9 @@ data: client.cnxns: "60" snap.retain: "3" purge.interval: "1" + client.port: "2181" + server.port: "2888" + election.port: "3888" --- apiVersion: policy/v1beta1 kind: PodDisruptionBudget @@ -63,9 +67,9 @@ spec: - zk-headless topologyKey: "kubernetes.io/hostname" containers: - - name: k8szk + - name: zk imagePullPolicy: Always - image: thingsboard/k8szk:k8test + image: thingsboard/zk:k8stest resources: requests: memory: "500Mi" @@ -84,48 +88,60 @@ spec: name: zk-config key: ensemble - name : ZK_REPLICAS - value: "3" + valueFrom: + configMapKeyRef: + name: zk-config + key: replicas - name : ZK_HEAP_SIZE valueFrom: configMapKeyRef: - name: zk-config - key: jvm.heap + name: zk-config + key: jvm.heap - name : ZK_TICK_TIME valueFrom: configMapKeyRef: - name: zk-config - key: tick + name: zk-config + key: tick - name : ZK_INIT_LIMIT valueFrom: configMapKeyRef: - name: zk-config - key: init + name: zk-config + key: init - name : ZK_SYNC_LIMIT valueFrom: configMapKeyRef: - name: zk-config - key: tick + name: zk-config + key: tick - name : ZK_MAX_CLIENT_CNXNS valueFrom: configMapKeyRef: - name: zk-config - key: client.cnxns + name: zk-config + key: client.cnxns - name: ZK_SNAP_RETAIN_COUNT valueFrom: configMapKeyRef: - name: zk-config - key: snap.retain + name: zk-config + key: snap.retain - name: ZK_PURGE_INTERVAL valueFrom: configMapKeyRef: - name: zk-config - key: purge.interval + name: zk-config + key: purge.interval - name: ZK_CLIENT_PORT - value: "2181" + valueFrom: + configMapKeyRef: + name: zk-config + key: client.port - name: ZK_SERVER_PORT - value: "2888" + valueFrom: + configMapKeyRef: + name: zk-config + key: server.port - name: ZK_ELECTION_PORT - value: "3888" + valueFrom: + configMapKeyRef: + name: zk-config + key: election.port command: - sh - -c @@ -143,16 +159,16 @@ spec: initialDelaySeconds: 15 timeoutSeconds: 5 volumeMounts: - - name: datadir + - name: zkdatadir mountPath: /var/lib/zookeeper securityContext: runAsUser: 1000 fsGroup: 1000 volumeClaimTemplates: - metadata: - name: datadir + name: zkdatadir annotations: - volume.alpha.kubernetes.io/storage-class: anything + volume.beta.kubernetes.io/storage-class: slow spec: accessModes: [ "ReadWriteOnce" ] resources: From 3a1eef449b024747dc271b361d8af5a31d89ff3b Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Wed, 10 May 2017 21:34:49 +0300 Subject: [PATCH 06/21] TB-58: k8s feature improvements --- docker/thingsboard/run_thingsboard.sh | 3 --- docker/thingsboard/thingsboard.yaml | 37 ++++++++------------------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/docker/thingsboard/run_thingsboard.sh b/docker/thingsboard/run_thingsboard.sh index 404cc8df9d..877fed7fec 100755 --- a/docker/thingsboard/run_thingsboard.sh +++ b/docker/thingsboard/run_thingsboard.sh @@ -34,9 +34,6 @@ done # Copying env variables into conf files printenv | awk -F "=" '{print "export " $1 "='\''" $2 "'\''"}' >> /usr/share/thingsboard/conf/thingsboard.conf -# Set env variable for RPC address -echo "export RPC_HOST='"$(hostname -f)"'" | tee -a /usr/share/thingsboard/conf/thingsboard.conf - cat /usr/share/thingsboard/conf/thingsboard.conf echo "Starting 'Thingsboard' service..." diff --git a/docker/thingsboard/thingsboard.yaml b/docker/thingsboard/thingsboard.yaml index a9c1df37d8..02326c1671 100644 --- a/docker/thingsboard/thingsboard.yaml +++ b/docker/thingsboard/thingsboard.yaml @@ -2,9 +2,9 @@ apiVersion: v1 kind: Service metadata: - name: tb-external-ip + name: tb-service labels: - app: tb-external-ip + app: tb-service spec: ports: - port: 8080 @@ -17,20 +17,6 @@ spec: app: tb type: LoadBalancer --- -apiVersion: v1 -kind: Service -metadata: - name: tb-headless - labels: - app: tb-headless -spec: - ports: - - port: 9001 - name: rpc - selector: - app: tb - clusterIP: None ---- apiVersion: policy/v1beta1 kind: PodDisruptionBudget metadata: @@ -55,14 +41,13 @@ kind: StatefulSet metadata: name: tb spec: - serviceName: "tb-headless" + serviceName: "tb-service" replicas: 2 template: metadata: labels: app: tb spec: - terminationGracePeriodSeconds: 10 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: @@ -71,7 +56,7 @@ spec: - key: "app" operator: In values: - - tb-headless + - tb-service topologyKey: "kubernetes.io/hostname" containers: - name: tb @@ -109,19 +94,17 @@ spec: configMapKeyRef: name: tb-config key: cassandra.url + - name : RPC_HOST + valueFrom: + fieldRef: + fieldPath: status.podIP command: - sh - -c - ./run_thingsboard.sh -# readinessProbe: -# httpGet: -# path: /login -# port: ui-port -# initialDelaySeconds: 30 -# periodSeconds: 10 livenessProbe: httpGet: path: /login port: ui-port - initialDelaySeconds: 30 - periodSeconds: 10 \ No newline at end of file + initialDelaySeconds: 120 + timeoutSeconds: 10 \ No newline at end of file From 2f5c9ecba5963e0199f061fa4cfb07d7e0147390 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Wed, 17 May 2017 12:08:10 +0300 Subject: [PATCH 07/21] improved docker makefiles --- docker/cassandra/Makefile | 6 +----- docker/thingsboard-db-schema/Makefile | 8 ++++---- docker/thingsboard/Makefile | 6 ++---- docker/zookeeper/Makefile | 4 ---- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/docker/cassandra/Makefile b/docker/cassandra/Makefile index ea71c6340c..cb577cb502 100644 --- a/docker/cassandra/Makefile +++ b/docker/cassandra/Makefile @@ -2,12 +2,8 @@ VERSION=k8stest PROJECT=thingsboard APP=cassandra -all: build - build: docker build --pull -t ${PROJECT}/${APP}:${VERSION} . push: build - docker push ${PROJECT}/${APP}:${VERSION} - -.PHONY: all build push \ No newline at end of file + docker push ${PROJECT}/${APP}:${VERSION} \ No newline at end of file diff --git a/docker/thingsboard-db-schema/Makefile b/docker/thingsboard-db-schema/Makefile index 653153940f..ef526e1a6a 100644 --- a/docker/thingsboard-db-schema/Makefile +++ b/docker/thingsboard-db-schema/Makefile @@ -2,12 +2,12 @@ VERSION=k8stest PROJECT=thingsboard APP=thingsboard-db-schema -all: build - build: + cp ../../dao/src/main/resources/schema.cql . + cp ../../dao/src/main/resources/demo-data.cql . + cp ../../dao/src/main/resources/system-data.cql . docker build --pull -t ${PROJECT}/${APP}:${VERSION} . push: build docker push ${PROJECT}/${APP}:${VERSION} - -.PHONY: all build push \ No newline at end of file + rm schema.cql demo-data.cql system-data.cql \ No newline at end of file diff --git a/docker/thingsboard/Makefile b/docker/thingsboard/Makefile index 29203e30d3..72ada4d0f7 100644 --- a/docker/thingsboard/Makefile +++ b/docker/thingsboard/Makefile @@ -2,12 +2,10 @@ VERSION=k8stest PROJECT=thingsboard APP=application -all: build - build: + cp ../../application/target/thingsboard.deb . docker build --pull -t ${PROJECT}/${APP}:${VERSION} . push: build docker push ${PROJECT}/${APP}:${VERSION} - -.PHONY: all build push \ No newline at end of file + rm thingsboard.deb \ No newline at end of file diff --git a/docker/zookeeper/Makefile b/docker/zookeeper/Makefile index 4c7a8c4007..b179f07291 100644 --- a/docker/zookeeper/Makefile +++ b/docker/zookeeper/Makefile @@ -2,12 +2,8 @@ VERSION=k8stest PROJECT=thingsboard APP=zk -all: build - build: docker build --pull -t ${PROJECT}/${APP}:${VERSION} . push: build docker push ${PROJECT}/${APP}:${VERSION} - -.PHONY: all build push From aaf3c5d4390fefd11d5ab69cc05d156eee6f7df2 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Wed, 17 May 2017 13:17:36 +0300 Subject: [PATCH 08/21] small docker makefiles fixes --- docker/thingsboard-db-schema/Makefile | 4 ++-- docker/thingsboard/Makefile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/thingsboard-db-schema/Makefile b/docker/thingsboard-db-schema/Makefile index ef526e1a6a..604520e90d 100644 --- a/docker/thingsboard-db-schema/Makefile +++ b/docker/thingsboard-db-schema/Makefile @@ -7,7 +7,7 @@ build: cp ../../dao/src/main/resources/demo-data.cql . cp ../../dao/src/main/resources/system-data.cql . docker build --pull -t ${PROJECT}/${APP}:${VERSION} . + rm schema.cql demo-data.cql system-data.cql push: build - docker push ${PROJECT}/${APP}:${VERSION} - rm schema.cql demo-data.cql system-data.cql \ No newline at end of file + docker push ${PROJECT}/${APP}:${VERSION} \ No newline at end of file diff --git a/docker/thingsboard/Makefile b/docker/thingsboard/Makefile index 72ada4d0f7..000968e447 100644 --- a/docker/thingsboard/Makefile +++ b/docker/thingsboard/Makefile @@ -5,7 +5,7 @@ APP=application build: cp ../../application/target/thingsboard.deb . docker build --pull -t ${PROJECT}/${APP}:${VERSION} . + rm thingsboard.deb push: build - docker push ${PROJECT}/${APP}:${VERSION} - rm thingsboard.deb \ No newline at end of file + docker push ${PROJECT}/${APP}:${VERSION} \ No newline at end of file From 7120d61f59eb1e72ab16c643ca95003e3ae93a2f Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 18 May 2017 21:09:54 +0300 Subject: [PATCH 09/21] Misc fixes after performance testing --- docker/cassandra/Dockerfile | 16 +++++++++++ docker/cassandra/cassandra.yaml | 27 ++++++++++++------- docker/cassandra/ready-probe.sh | 5 ++-- docker/common/common.yaml | 24 +++++++++++++++++ .../thingsboard-db-schema.yaml | 16 +++++++++++ docker/thingsboard/thingsboard.yaml | 23 +++++++++++----- docker/zookeeper/Dockerfile | 16 +++++++++++ docker/zookeeper/zkGenConfig.sh | 4 ++- docker/zookeeper/zkOk.sh | 4 ++- docker/zookeeper/zookeeper.yaml | 20 +++++++++++--- 10 files changed, 131 insertions(+), 24 deletions(-) diff --git a/docker/cassandra/Dockerfile b/docker/cassandra/Dockerfile index 72084cd0af..ec8117358f 100644 --- a/docker/cassandra/Dockerfile +++ b/docker/cassandra/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + FROM cassandra:3.9 COPY ready-probe.sh / diff --git a/docker/cassandra/cassandra.yaml b/docker/cassandra/cassandra.yaml index c3772b15e1..6da5532c3f 100644 --- a/docker/cassandra/cassandra.yaml +++ b/docker/cassandra/cassandra.yaml @@ -1,3 +1,19 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + apiVersion: v1 kind: Service metadata: @@ -49,13 +65,6 @@ spec: name: cql - containerPort: 9160 name: thrift - resources: - limits: - cpu: "500m" - memory: 1Gi - requests: - cpu: "500m" - memory: 1Gi securityContext: capabilities: add: @@ -104,7 +113,7 @@ spec: - metadata: name: cassandra-data annotations: - volume.beta.kubernetes.io/storage-class: slow + volume.beta.kubernetes.io/storage-class: fast spec: accessModes: [ "ReadWriteOnce" ] resources: @@ -113,7 +122,7 @@ spec: - metadata: name: cassandra-commitlog annotations: - volume.beta.kubernetes.io/storage-class: slow + volume.beta.kubernetes.io/storage-class: fast spec: accessModes: [ "ReadWriteOnce" ] resources: diff --git a/docker/cassandra/ready-probe.sh b/docker/cassandra/ready-probe.sh index 989f4d90a1..68faf927fe 100755 --- a/docker/cassandra/ready-probe.sh +++ b/docker/cassandra/ready-probe.sh @@ -1,6 +1,6 @@ #!/bin/bash - -# Copyright 2016 The Kubernetes Authors. +# +# Copyright © 2016-2017 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# if [[ $(nodetool status | grep $POD_IP) == *"UN"* ]]; then if [[ $DEBUG ]]; then diff --git a/docker/common/common.yaml b/docker/common/common.yaml index 610c027911..f650118efd 100644 --- a/docker/common/common.yaml +++ b/docker/common/common.yaml @@ -1,3 +1,19 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + --- apiVersion: storage.k8s.io/v1beta1 kind: StorageClass @@ -6,4 +22,12 @@ metadata: provisioner: kubernetes.io/gce-pd parameters: type: pd-standard +--- +apiVersion: storage.k8s.io/v1beta1 +kind: StorageClass +metadata: + name: fast +provisioner: kubernetes.io/gce-pd +parameters: + type: pd-ssd --- \ No newline at end of file diff --git a/docker/thingsboard-db-schema/thingsboard-db-schema.yaml b/docker/thingsboard-db-schema/thingsboard-db-schema.yaml index dbc4f587f2..6d6040f2eb 100644 --- a/docker/thingsboard-db-schema/thingsboard-db-schema.yaml +++ b/docker/thingsboard-db-schema/thingsboard-db-schema.yaml @@ -1,3 +1,19 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + apiVersion: v1 kind: Pod metadata: diff --git a/docker/thingsboard/thingsboard.yaml b/docker/thingsboard/thingsboard.yaml index 02326c1671..6ef5ab16b4 100644 --- a/docker/thingsboard/thingsboard.yaml +++ b/docker/thingsboard/thingsboard.yaml @@ -1,3 +1,19 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + --- apiVersion: v1 kind: Service @@ -71,13 +87,6 @@ spec: name: coap - containerPort: 9001 name: rpc - resources: - limits: - cpu: "250m" - memory: "500Mi" - requests: - cpu: "250m" - memory: "500Mi" env: - name: ZOOKEEPER_ENABLED valueFrom: diff --git a/docker/zookeeper/Dockerfile b/docker/zookeeper/Dockerfile index 7752f93b3a..7d3480e825 100644 --- a/docker/zookeeper/Dockerfile +++ b/docker/zookeeper/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + FROM ubuntu:16.04 ENV ZK_USER=zookeeper \ ZK_DATA_DIR=/var/lib/zookeeper/data \ diff --git a/docker/zookeeper/zkGenConfig.sh b/docker/zookeeper/zkGenConfig.sh index 0b3365bcac..02fde70fa1 100755 --- a/docker/zookeeper/zkGenConfig.sh +++ b/docker/zookeeper/zkGenConfig.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors. +# +# Copyright © 2016-2017 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# ZK_USER=${ZK_USER:-"zookeeper"} ZK_LOG_LEVEL=${ZK_LOG_LEVEL:-"INFO"} diff --git a/docker/zookeeper/zkOk.sh b/docker/zookeeper/zkOk.sh index dbe417682f..6dd38ca030 100755 --- a/docker/zookeeper/zkOk.sh +++ b/docker/zookeeper/zkOk.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -# Copyright 2016 The Kubernetes Authors. +# +# Copyright © 2016-2017 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# # zkOk.sh uses the ruok ZooKeeper four letter work to determine if the instance # is health. The $? variable will be set to 0 if server responds that it is diff --git a/docker/zookeeper/zookeeper.yaml b/docker/zookeeper/zookeeper.yaml index 00bca9c902..ed7a9f6ba2 100644 --- a/docker/zookeeper/zookeeper.yaml +++ b/docker/zookeeper/zookeeper.yaml @@ -1,3 +1,19 @@ +# +# Copyright © 2016-2017 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + apiVersion: v1 kind: Service metadata: @@ -70,10 +86,6 @@ spec: - name: zk imagePullPolicy: Always image: thingsboard/zk:k8stest - resources: - requests: - memory: "500Mi" - cpu: "250m" ports: - containerPort: 2181 name: client From 2b18ed7a9294d72ecfcf24534dc2b70cb8592fbf Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 19 May 2017 11:46:15 +0300 Subject: [PATCH 10/21] Misc improvements --- docker/cassandra/cassandra.yaml | 10 ++++++---- docker/thingsboard/thingsboard.yaml | 6 ++++-- docker/zookeeper/zookeeper.yaml | 6 ++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docker/cassandra/cassandra.yaml b/docker/cassandra/cassandra.yaml index 6da5532c3f..24312ae562 100644 --- a/docker/cassandra/cassandra.yaml +++ b/docker/cassandra/cassandra.yaml @@ -34,12 +34,14 @@ metadata: name: cassandra spec: serviceName: cassandra-headless - replicas: 3 + replicas: 2 template: metadata: labels: app: cassandra spec: + nodeSelector: + machinetype: other affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: @@ -75,7 +77,7 @@ spec: command: ["/bin/sh", "-c", "PID=$(pidof java) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done"] env: - name: MAX_HEAP_SIZE - value: 512M + value: 2048M - name: HEAP_NEWSIZE value: 100M - name: CASSANDRA_SEEDS @@ -118,7 +120,7 @@ spec: accessModes: [ "ReadWriteOnce" ] resources: requests: - storage: 2Gi + storage: 3Gi - metadata: name: cassandra-commitlog annotations: @@ -127,4 +129,4 @@ spec: accessModes: [ "ReadWriteOnce" ] resources: requests: - storage: 1Gi \ No newline at end of file + storage: 2Gi \ No newline at end of file diff --git a/docker/thingsboard/thingsboard.yaml b/docker/thingsboard/thingsboard.yaml index 6ef5ab16b4..f03f49bcf1 100644 --- a/docker/thingsboard/thingsboard.yaml +++ b/docker/thingsboard/thingsboard.yaml @@ -41,7 +41,7 @@ spec: selector: matchLabels: app: tb - minAvailable: 2 + minAvailable: 3 --- apiVersion: v1 kind: ConfigMap @@ -58,12 +58,14 @@ metadata: name: tb spec: serviceName: "tb-service" - replicas: 2 + replicas: 3 template: metadata: labels: app: tb spec: + nodeSelector: + machinetype: tb affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: diff --git a/docker/zookeeper/zookeeper.yaml b/docker/zookeeper/zookeeper.yaml index ed7a9f6ba2..062d8cc4ee 100644 --- a/docker/zookeeper/zookeeper.yaml +++ b/docker/zookeeper/zookeeper.yaml @@ -35,7 +35,7 @@ kind: ConfigMap metadata: name: zk-config data: - ensemble: "zk-0;zk-1;zk-2" + ensemble: "zk-0;zk-1" replicas: "3" jvm.heap: "500m" tick: "2000" @@ -64,7 +64,7 @@ metadata: name: zk spec: serviceName: zk-headless - replicas: 3 + replicas: 2 template: metadata: labels: @@ -72,6 +72,8 @@ spec: annotations: pod.alpha.kubernetes.io/initialized: "true" spec: + nodeSelector: + machinetype: other affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: From 8c50c63ca970ae36d2bd1b86b3ea998e39efad7e Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 23 May 2017 09:25:31 +0300 Subject: [PATCH 11/21] Docker SSL support --- .../src/main/resources/thingsboard.yml | 46 ++++++++++++------- .../dao/cache/ServiceCacheConfiguration.java | 1 - docker/docker-compose.yml | 8 ++-- docker/thingsboard.env | 6 ++- docker/thingsboard/build_and_deploy.sh | 7 +-- .../mqtt/MqttSslHandlerProvider.java | 2 +- 6 files changed, 41 insertions(+), 29 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index e64e9cd95c..f015aa156e 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -19,12 +19,18 @@ server: address: "${HTTP_BIND_ADDRESS:0.0.0.0}" # Server bind port port: "${HTTP_BIND_PORT:8080}" -# Uncomment the following section to enable ssl -# ssl: -# key-store: classpath:keystore/keystore.p12 -# key-store-password: thingsboard -# keyStoreType: PKCS12 -# keyAlias: tomcat + # Server SSL configuration + ssl: + # Enable/disable SSL support + enabled: "${SSL_ENABLED:false}" + # Path to the key store that holds the SSL certificate + key-store: "${SSL_KEY_STORE:classpath:keystore/keystore.p12}" + # Password used to access the key store + key-store-password: "${SSL_KEY_STORE_PASSWORD:thingsboard}" + # Type of the key store + key-store-type: "${SSL_KEY_STORE_TYPE:PKCS12}" + # Alias that identifies the key in the key store + key-alias: "${SSL_KEY_ALIAS:tomcat}" # Zookeeper connection parameters. Used for service discovery. zk: @@ -60,10 +66,10 @@ plugins: # JWT Token parameters security.jwt: - tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:900}" # Number of seconds (15 mins) - refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:3600}" # Seconds (1 hour) - tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" - tokenSigningKey: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}" + token-expiration-time: "${JWT_TOKEN_EXPIRATION_TIME:900}" # Number of seconds (15 mins) + refresh-token-exp-time: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:3600}" # Seconds (1 hour) + token-issuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" + token-signing-key: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}" # Device communication protocol parameters http: @@ -72,19 +78,25 @@ http: # MQTT server parameters mqtt: bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}" - bind_port: "${MQTT_BIND_PORT:1883}" + bind_port: "${MQTT_BIND_PORT:1884}" adaptor: "${MQTT_ADAPTOR_NAME:JsonMqttAdaptor}" timeout: "${MQTT_TIMEOUT:10000}" netty: leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}" boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}" worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}" -# Uncomment the following lines to enable ssl for MQTT -# ssl: -# key_store: mqttserver.jks -# key_store_password: server_ks_password -# key_password: server_key_password -# key_store_type: JKS + # MQTT SSL configuration + ssl: + # Enable/disable SSL support + enabled: "${MQTT_SSL_ENABLED:false}" + # Path to the key store that holds the SSL certificate + key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" + # Password used to access the key store + key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" + # Password used to access the key + key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" + # Type of the key store + key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}" # CoAP server parameters coap: diff --git a/dao/src/main/java/org/thingsboard/server/dao/cache/ServiceCacheConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/cache/ServiceCacheConfiguration.java index b4fbc65507..7c435bf779 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cache/ServiceCacheConfiguration.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cache/ServiceCacheConfiguration.java @@ -45,7 +45,6 @@ public class ServiceCacheConfiguration { @Value("${cache.device_credentials.time_to_live}") private Integer cacheDeviceCredentialsTTL; - @Value("${zk.enabled}") private boolean zkEnabled; @Value("${zk.url}") diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index d19332b8de..b3b182364c 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -18,13 +18,15 @@ version: '2' services: thingsboard: - image: "thingsboard/application:1.2.2" + image: "thingsboard/application:1.2.3-test" ports: - - "8080:8080" - - "1883:1883" + - "8443:8443" + - "1884:1883" - "5683:5683/udp" env_file: - thingsboard.env + volumes: + - "~/keystore.p12:/root/keystore.p12" entrypoint: ./run_thingsboard.sh thingsboard-db-schema: image: "thingsboard/thingsboard-db-schema:1.2.2" diff --git a/docker/thingsboard.env b/docker/thingsboard.env index 2325790cd6..5d9ca6ddf3 100644 --- a/docker/thingsboard.env +++ b/docker/thingsboard.env @@ -5,4 +5,8 @@ ZOOKEEPER_URL=zk:2181 MQTT_BIND_ADDRESS=0.0.0.0 MQTT_BIND_PORT=1883 COAP_BIND_ADDRESS=0.0.0.0 -COAP_BIND_PORT=5683 \ No newline at end of file +COAP_BIND_PORT=5683 + +SSL_ENABLED=true +SSL_KEY_STORE=/root/keystore.p12 +HTTP_BIND_PORT=8443 \ No newline at end of file diff --git a/docker/thingsboard/build_and_deploy.sh b/docker/thingsboard/build_and_deploy.sh index 7c02de571c..58d7cd65e3 100755 --- a/docker/thingsboard/build_and_deploy.sh +++ b/docker/thingsboard/build_and_deploy.sh @@ -18,9 +18,4 @@ cp ../../application/target/thingsboard.deb thingsboard.deb -docker build -t thingsboard/application:1.2.2 -t thingsboard/application:latest . - -docker login - -docker push thingsboard/application:1.2.2 -docker push thingsboard/application:latest \ No newline at end of file +docker build -t thingsboard/application:1.2.3-test . \ No newline at end of file diff --git a/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java b/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java index 80e4e011fa..aed9a0c4d4 100644 --- a/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java +++ b/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java @@ -41,7 +41,7 @@ import java.security.cert.X509Certificate; */ @Slf4j @Component("MqttSslHandlerProvider") -@ConditionalOnProperty(prefix = "mqtt.ssl", value = "key-store", havingValue = "", matchIfMissing = false) +@ConditionalOnProperty(prefix = "mqtt.ssl", value = "enabled", havingValue = "true", matchIfMissing = false) public class MqttSslHandlerProvider { public static final String TLS = "TLS"; From 5da5a1a1347540c0a2091f4ea37353d4814aaddc Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 24 May 2017 15:24:48 +0300 Subject: [PATCH 12/21] removed unnecessary config options --- docker/docker-compose.yml | 2 -- docker/thingsboard.env | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index e5015f789f..2617133206 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -25,8 +25,6 @@ services: - "5683:5683/udp" env_file: - thingsboard.env - volumes: - - "~/keystore.p12:/root/keystore.p12" entrypoint: ./run_thingsboard.sh thingsboard-db-schema: image: "thingsboard/thingsboard-db-schema:1.2.3" diff --git a/docker/thingsboard.env b/docker/thingsboard.env index 5d9ca6ddf3..2325790cd6 100644 --- a/docker/thingsboard.env +++ b/docker/thingsboard.env @@ -5,8 +5,4 @@ ZOOKEEPER_URL=zk:2181 MQTT_BIND_ADDRESS=0.0.0.0 MQTT_BIND_PORT=1883 COAP_BIND_ADDRESS=0.0.0.0 -COAP_BIND_PORT=5683 - -SSL_ENABLED=true -SSL_KEY_STORE=/root/keystore.p12 -HTTP_BIND_PORT=8443 \ No newline at end of file +COAP_BIND_PORT=5683 \ No newline at end of file From 9c29deba7327f0759fff94dd87f6249308f59adf Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 24 May 2017 15:31:37 +0300 Subject: [PATCH 13/21] Revert to default values --- application/src/main/resources/thingsboard.yml | 2 +- docker/docker-compose.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index ce6ecb1ac2..24cea0e4af 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -78,7 +78,7 @@ http: # MQTT server parameters mqtt: bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}" - bind_port: "${MQTT_BIND_PORT:1884}" + bind_port: "${MQTT_BIND_PORT:1883}" adaptor: "${MQTT_ADAPTOR_NAME:JsonMqttAdaptor}" timeout: "${MQTT_TIMEOUT:10000}" netty: diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 2617133206..97873e82ce 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -20,8 +20,8 @@ services: thingsboard: image: "thingsboard/application:1.2.3" ports: - - "8443:8443" - - "1884:1883" + - "8080:8080" + - "1883:1883" - "5683:5683/udp" env_file: - thingsboard.env From 868f5d3ca12513cc3abc08b94787b5d18464dddc Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 24 May 2017 16:17:23 +0300 Subject: [PATCH 14/21] Renaming + refactoring --- docker/.env | 3 ++- docker/docker-compose.random.yml | 2 +- docker/docker-compose.static.yml | 2 +- docker/docker-compose.yml | 23 ++++++++++--------- .../Dockerfile | 4 ++-- .../Makefile | 2 +- .../install-schema.sh} | 0 .../tb-cassandra-schema.yaml} | 8 +++---- docker/{thingsboard.env => tb.env} | 2 +- docker/{thingsboard => tb}/Dockerfile | 4 ++-- docker/{thingsboard => tb}/Makefile | 0 .../run-application.sh} | 6 ++--- .../thingsboard.yaml => tb/tb.yaml} | 2 +- docker/zookeeper/Dockerfile | 2 +- .../{zkGenConfig.sh => zk-gen-config.sh} | 0 docker/zookeeper/{zkOk.sh => zk-ok.sh} | 2 +- docker/zookeeper/zookeeper.yaml | 6 ++--- 17 files changed, 35 insertions(+), 33 deletions(-) rename docker/{thingsboard-db-schema => tb-cassandra-schema}/Dockerfile (90%) rename docker/{thingsboard-db-schema => tb-cassandra-schema}/Makefile (81%) rename docker/{thingsboard-db-schema/install_schema.sh => tb-cassandra-schema/install-schema.sh} (100%) rename docker/{thingsboard-db-schema/thingsboard-db-schema.yaml => tb-cassandra-schema/tb-cassandra-schema.yaml} (85%) rename docker/{thingsboard.env => tb.env} (72%) rename docker/{thingsboard => tb}/Dockerfile (88%) rename docker/{thingsboard => tb}/Makefile (100%) rename docker/{thingsboard/run_thingsboard.sh => tb/run-application.sh} (84%) rename docker/{thingsboard/thingsboard.yaml => tb/tb.yaml} (97%) rename docker/zookeeper/{zkGenConfig.sh => zk-gen-config.sh} (100%) rename docker/zookeeper/{zkOk.sh => zk-ok.sh} (91%) diff --git a/docker/.env b/docker/.env index f7cecd9ab6..c03637ecd5 100644 --- a/docker/.env +++ b/docker/.env @@ -3,4 +3,5 @@ CASSANDRA_DATA_DIR=/home/docker/cassandra_volume # cassandra schema container environment variables SKIP_SCHEMA_CREATION=false SKIP_SYSTEM_DATA=true -SKIP_DEMO_DATA=true \ No newline at end of file +SKIP_DEMO_DATA=true +CASSANDRA_URL=cassandra \ No newline at end of file diff --git a/docker/docker-compose.random.yml b/docker/docker-compose.random.yml index 0e60e08da5..f066c5cad5 100644 --- a/docker/docker-compose.random.yml +++ b/docker/docker-compose.random.yml @@ -17,7 +17,7 @@ version: '2' services: - db: + cassandra: ports: - "9042" - "9160" diff --git a/docker/docker-compose.static.yml b/docker/docker-compose.static.yml index 80cc6a946a..5471cb2339 100644 --- a/docker/docker-compose.static.yml +++ b/docker/docker-compose.static.yml @@ -17,7 +17,7 @@ version: '2' services: - db: + cassandra: ports: - "9042:9042" - "9160:9160" diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 893b02f5c1..498080447d 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -17,26 +17,27 @@ version: '2' services: - thingsboard: - image: "thingsboard/application:1.2.3" + tb: + image: "thingsboard/application:k8stest" ports: - "8080:8080" - - "1883:1883" + - "1884:1883" - "5683:5683/udp" env_file: - - thingsboard.env - entrypoint: ./run_thingsboard.sh - thingsboard-db-schema: - image: "thingsboard/thingsboard-db-schema:1.2.3" + - tb.env + entrypoint: ./run-application.sh + tb-cassandra-schema: + image: "thingsboard/tb-cassandra-schema:k8stest" environment: - SKIP_SCHEMA_CREATION=${SKIP_SCHEMA_CREATION} - SKIP_SYSTEM_DATA=${SKIP_SYSTEM_DATA} - SKIP_DEMO_DATA=${SKIP_DEMO_DATA} - entrypoint: ./install_schema.sh - db: - image: "cassandra:3.9" + - CASSANDRA_URL=${CASSANDRA_URL} + entrypoint: ./install-schema.sh + cassandra: + image: "thingsboard/cassandra:k8stest" volumes: - "${CASSANDRA_DATA_DIR}:/var/lib/cassandra" zk: - image: "zookeeper:3.4.9" + image: "thingsboard/zk:k8stest" restart: always diff --git a/docker/thingsboard-db-schema/Dockerfile b/docker/tb-cassandra-schema/Dockerfile similarity index 90% rename from docker/thingsboard-db-schema/Dockerfile rename to docker/tb-cassandra-schema/Dockerfile index a4b4c8778e..d8660d450a 100644 --- a/docker/thingsboard-db-schema/Dockerfile +++ b/docker/tb-cassandra-schema/Dockerfile @@ -16,12 +16,12 @@ FROM cassandra:3.9 -ADD install_schema.sh /root/install_schema.sh +ADD install-schema.sh /root/install-schema.sh RUN apt-get update \ && apt-get install -y nmap -RUN chmod +x /root/install_schema.sh +RUN chmod +x /root/install-schema.sh ADD schema.cql /root/schema.cql ADD demo-data.cql /root/demo-data.cql diff --git a/docker/thingsboard-db-schema/Makefile b/docker/tb-cassandra-schema/Makefile similarity index 81% rename from docker/thingsboard-db-schema/Makefile rename to docker/tb-cassandra-schema/Makefile index 604520e90d..aa18c4da2f 100644 --- a/docker/thingsboard-db-schema/Makefile +++ b/docker/tb-cassandra-schema/Makefile @@ -1,6 +1,6 @@ VERSION=k8stest PROJECT=thingsboard -APP=thingsboard-db-schema +APP=tb-cassandra-schema build: cp ../../dao/src/main/resources/schema.cql . diff --git a/docker/thingsboard-db-schema/install_schema.sh b/docker/tb-cassandra-schema/install-schema.sh similarity index 100% rename from docker/thingsboard-db-schema/install_schema.sh rename to docker/tb-cassandra-schema/install-schema.sh diff --git a/docker/thingsboard-db-schema/thingsboard-db-schema.yaml b/docker/tb-cassandra-schema/tb-cassandra-schema.yaml similarity index 85% rename from docker/thingsboard-db-schema/thingsboard-db-schema.yaml rename to docker/tb-cassandra-schema/tb-cassandra-schema.yaml index 6d6040f2eb..9376d48a75 100644 --- a/docker/thingsboard-db-schema/thingsboard-db-schema.yaml +++ b/docker/tb-cassandra-schema/tb-cassandra-schema.yaml @@ -17,12 +17,12 @@ apiVersion: v1 kind: Pod metadata: - name: tb-db-schema + name: tb-cassandra-schema spec: containers: - - name: tb-db-schema + - name: tb-cassandra-schema imagePullPolicy: Always - image: thingsboard/thingsboard-db-schema:k8stest + image: thingsboard/tb-cassandra-schema:k8stest env: - name: SKIP_SCHEMA_CREATION value: "false" @@ -35,5 +35,5 @@ spec: command: - sh - -c - - ./install_schema.sh + - ./install-schema.sh restartPolicy: Never \ No newline at end of file diff --git a/docker/thingsboard.env b/docker/tb.env similarity index 72% rename from docker/thingsboard.env rename to docker/tb.env index 2325790cd6..3850e3dee9 100644 --- a/docker/thingsboard.env +++ b/docker/tb.env @@ -1,6 +1,6 @@ #Thingsboard server configuration -CASSANDRA_URL=db:9042 +CASSANDRA_URL=cassandra:9042 ZOOKEEPER_URL=zk:2181 MQTT_BIND_ADDRESS=0.0.0.0 MQTT_BIND_PORT=1883 diff --git a/docker/thingsboard/Dockerfile b/docker/tb/Dockerfile similarity index 88% rename from docker/thingsboard/Dockerfile rename to docker/tb/Dockerfile index cbc1a3fcad..c2e2d7b631 100644 --- a/docker/thingsboard/Dockerfile +++ b/docker/tb/Dockerfile @@ -16,9 +16,9 @@ FROM openjdk:8-jre -ADD run_thingsboard.sh /root/run_thingsboard.sh +ADD run-application.sh /root/run-application.sh ADD thingsboard.deb /root/thingsboard.deb -RUN chmod +x /root/run_thingsboard.sh +RUN chmod +x /root/run-application.sh WORKDIR /root diff --git a/docker/thingsboard/Makefile b/docker/tb/Makefile similarity index 100% rename from docker/thingsboard/Makefile rename to docker/tb/Makefile diff --git a/docker/thingsboard/run_thingsboard.sh b/docker/tb/run-application.sh similarity index 84% rename from docker/thingsboard/run_thingsboard.sh rename to docker/tb/run-application.sh index 877fed7fec..461774cfa6 100755 --- a/docker/thingsboard/run_thingsboard.sh +++ b/docker/tb/run-application.sh @@ -21,12 +21,12 @@ dpkg -i /root/thingsboard.deb reachable=0 while [ $reachable -eq 0 ]; do - echo "thingsboard-db-schema container is still in progress. waiting until it completed..." + echo "tb-cassandra-schema container is still in progress. waiting until it completed..." sleep 3 - ping -q -c 1 thingsboard-db-schema > /dev/null 2>&1 + ping -q -c 1 tb-cassandra-schema > /dev/null 2>&1 if [ "$?" -ne 0 ]; then - echo "thingsboard-db-schema container completed!" + echo "tb-cassandra-schema container completed!" reachable=1 fi done diff --git a/docker/thingsboard/thingsboard.yaml b/docker/tb/tb.yaml similarity index 97% rename from docker/thingsboard/thingsboard.yaml rename to docker/tb/tb.yaml index f03f49bcf1..b65a2e90c5 100644 --- a/docker/thingsboard/thingsboard.yaml +++ b/docker/tb/tb.yaml @@ -112,7 +112,7 @@ spec: command: - sh - -c - - ./run_thingsboard.sh + - ./run-application.sh livenessProbe: httpGet: path: /login diff --git a/docker/zookeeper/Dockerfile b/docker/zookeeper/Dockerfile index 7d3480e825..5ec1ac9be1 100644 --- a/docker/zookeeper/Dockerfile +++ b/docker/zookeeper/Dockerfile @@ -55,7 +55,7 @@ RUN set -x \ && rm -rf /var/lib/apt/lists/* #Copy configuration generator script to bin -COPY zkGenConfig.sh zkOk.sh /opt/zookeeper/bin/ +COPY zk-gen-config.sh zk-ok.sh /opt/zookeeper/bin/ # Create a user for the zookeeper process and configure file system ownership # for nessecary directories and symlink the distribution as a user executable diff --git a/docker/zookeeper/zkGenConfig.sh b/docker/zookeeper/zk-gen-config.sh similarity index 100% rename from docker/zookeeper/zkGenConfig.sh rename to docker/zookeeper/zk-gen-config.sh diff --git a/docker/zookeeper/zkOk.sh b/docker/zookeeper/zk-ok.sh similarity index 91% rename from docker/zookeeper/zkOk.sh rename to docker/zookeeper/zk-ok.sh index 449a0fdfa0..f2a2d32ae3 100755 --- a/docker/zookeeper/zkOk.sh +++ b/docker/zookeeper/zk-ok.sh @@ -15,7 +15,7 @@ # limitations under the License. # -# zkOk.sh uses the ruok ZooKeeper four letter work to determine if the instance +# zk-ok.sh uses the ruok ZooKeeper four letter work to determine if the instance # is health. The $? variable will be set to 0 if server responds that it is # healthy, or 1 if the server fails to respond. diff --git a/docker/zookeeper/zookeeper.yaml b/docker/zookeeper/zookeeper.yaml index 062d8cc4ee..4b8501d524 100644 --- a/docker/zookeeper/zookeeper.yaml +++ b/docker/zookeeper/zookeeper.yaml @@ -159,17 +159,17 @@ spec: command: - sh - -c - - zkGenConfig.sh && zkServer.sh start-foreground + - zk-gen-config.sh && zkServer.sh start-foreground readinessProbe: exec: command: - - "zkOk.sh" + - "zk-ok.sh" initialDelaySeconds: 15 timeoutSeconds: 5 livenessProbe: exec: command: - - "zkOk.sh" + - "zk-ok.sh" initialDelaySeconds: 15 timeoutSeconds: 5 volumeMounts: From 8ed9cf8620351b3e80e30a72a83b0f8ced1f1366 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 24 May 2017 16:37:20 +0300 Subject: [PATCH 15/21] Removed cassandra custom image --- docker/cassandra/Dockerfile | 21 --------------------- docker/cassandra/Makefile | 9 --------- docker/cassandra/cassandra.yaml | 2 +- docker/cassandra/ready-probe.sh | 28 ---------------------------- docker/docker-compose.random.yml | 26 -------------------------- docker/docker-compose.yml | 9 +++++++-- 6 files changed, 8 insertions(+), 87 deletions(-) delete mode 100644 docker/cassandra/Dockerfile delete mode 100644 docker/cassandra/Makefile delete mode 100755 docker/cassandra/ready-probe.sh delete mode 100644 docker/docker-compose.random.yml diff --git a/docker/cassandra/Dockerfile b/docker/cassandra/Dockerfile deleted file mode 100644 index ec8117358f..0000000000 --- a/docker/cassandra/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright © 2016-2017 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -FROM cassandra:3.9 - -COPY ready-probe.sh / - -CMD ["cassandra", "-f"] \ No newline at end of file diff --git a/docker/cassandra/Makefile b/docker/cassandra/Makefile deleted file mode 100644 index cb577cb502..0000000000 --- a/docker/cassandra/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -VERSION=k8stest -PROJECT=thingsboard -APP=cassandra - -build: - docker build --pull -t ${PROJECT}/${APP}:${VERSION} . - -push: build - docker push ${PROJECT}/${APP}:${VERSION} \ No newline at end of file diff --git a/docker/cassandra/cassandra.yaml b/docker/cassandra/cassandra.yaml index 24312ae562..e54d47b07a 100644 --- a/docker/cassandra/cassandra.yaml +++ b/docker/cassandra/cassandra.yaml @@ -54,7 +54,7 @@ spec: topologyKey: "kubernetes.io/hostname" containers: - name: cassandra - image: thingsboard/cassandra:k8stest + image: cassandra:3.9 imagePullPolicy: Always ports: - containerPort: 7000 diff --git a/docker/cassandra/ready-probe.sh b/docker/cassandra/ready-probe.sh deleted file mode 100755 index 68faf927fe..0000000000 --- a/docker/cassandra/ready-probe.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Copyright © 2016-2017 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -if [[ $(nodetool status | grep $POD_IP) == *"UN"* ]]; then - if [[ $DEBUG ]]; then - echo "UN"; - fi - exit 0; -else - if [[ $DEBUG ]]; then - echo "Not Up"; - fi - exit 1; -fi \ No newline at end of file diff --git a/docker/docker-compose.random.yml b/docker/docker-compose.random.yml deleted file mode 100644 index f066c5cad5..0000000000 --- a/docker/docker-compose.random.yml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright © 2016-2017 The Thingsboard Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -version: '2' - -services: - cassandra: - ports: - - "9042" - - "9160" - zk: - ports: - - "2181" diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 498080447d..c86f20d98c 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -35,9 +35,14 @@ services: - CASSANDRA_URL=${CASSANDRA_URL} entrypoint: ./install-schema.sh cassandra: - image: "thingsboard/cassandra:k8stest" + image: "cassandra:3.9" + ports: + - "9042" + - "9160" volumes: - "${CASSANDRA_DATA_DIR}:/var/lib/cassandra" zk: - image: "thingsboard/zk:k8stest" + image: "zookeeper:3.4.9" + ports: + - "2181" restart: always From d850f92c7b7dfdaba37e95151cceeddcabc19d05 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 24 May 2017 16:40:19 +0300 Subject: [PATCH 16/21] Fixed version --- docker/docker-compose.yml | 6 +++--- docker/tb-cassandra-schema/Makefile | 2 +- docker/tb-cassandra-schema/tb-cassandra-schema.yaml | 2 +- docker/tb/Makefile | 2 +- docker/tb/tb.yaml | 2 +- docker/zookeeper/Makefile | 2 +- docker/zookeeper/zookeeper.yaml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index c86f20d98c..ebf1202061 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -18,16 +18,16 @@ version: '2' services: tb: - image: "thingsboard/application:k8stest" + image: "thingsboard/application:1.2.4" ports: - "8080:8080" - - "1884:1883" + - "1883:1883" - "5683:5683/udp" env_file: - tb.env entrypoint: ./run-application.sh tb-cassandra-schema: - image: "thingsboard/tb-cassandra-schema:k8stest" + image: "thingsboard/tb-cassandra-schema:1.2.4" environment: - SKIP_SCHEMA_CREATION=${SKIP_SCHEMA_CREATION} - SKIP_SYSTEM_DATA=${SKIP_SYSTEM_DATA} diff --git a/docker/tb-cassandra-schema/Makefile b/docker/tb-cassandra-schema/Makefile index aa18c4da2f..c3f2820d07 100644 --- a/docker/tb-cassandra-schema/Makefile +++ b/docker/tb-cassandra-schema/Makefile @@ -1,4 +1,4 @@ -VERSION=k8stest +VERSION=1.2.4 PROJECT=thingsboard APP=tb-cassandra-schema diff --git a/docker/tb-cassandra-schema/tb-cassandra-schema.yaml b/docker/tb-cassandra-schema/tb-cassandra-schema.yaml index 9376d48a75..e3340a438a 100644 --- a/docker/tb-cassandra-schema/tb-cassandra-schema.yaml +++ b/docker/tb-cassandra-schema/tb-cassandra-schema.yaml @@ -22,7 +22,7 @@ spec: containers: - name: tb-cassandra-schema imagePullPolicy: Always - image: thingsboard/tb-cassandra-schema:k8stest + image: thingsboard/tb-cassandra-schema:1.2.4 env: - name: SKIP_SCHEMA_CREATION value: "false" diff --git a/docker/tb/Makefile b/docker/tb/Makefile index 000968e447..afd1f807da 100644 --- a/docker/tb/Makefile +++ b/docker/tb/Makefile @@ -1,4 +1,4 @@ -VERSION=k8stest +VERSION=1.2.4 PROJECT=thingsboard APP=application diff --git a/docker/tb/tb.yaml b/docker/tb/tb.yaml index b65a2e90c5..15ed1939d5 100644 --- a/docker/tb/tb.yaml +++ b/docker/tb/tb.yaml @@ -79,7 +79,7 @@ spec: containers: - name: tb imagePullPolicy: Always - image: thingsboard/application:k8stest + image: thingsboard/application:1.2.4 ports: - containerPort: 8080 name: ui diff --git a/docker/zookeeper/Makefile b/docker/zookeeper/Makefile index b179f07291..6e4ef125ff 100644 --- a/docker/zookeeper/Makefile +++ b/docker/zookeeper/Makefile @@ -1,4 +1,4 @@ -VERSION=k8stest +VERSION=1.2.4 PROJECT=thingsboard APP=zk diff --git a/docker/zookeeper/zookeeper.yaml b/docker/zookeeper/zookeeper.yaml index 4b8501d524..d027f8e6d5 100644 --- a/docker/zookeeper/zookeeper.yaml +++ b/docker/zookeeper/zookeeper.yaml @@ -87,7 +87,7 @@ spec: containers: - name: zk imagePullPolicy: Always - image: thingsboard/zk:k8stest + image: thingsboard/zk:1.2.4 ports: - containerPort: 2181 name: client From 9a6d98444172b0fd55188bbd46f475a62e251825 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 24 May 2017 16:49:27 +0300 Subject: [PATCH 17/21] Fixed cassandra schema instance name --- docker/tb-cassandra-schema/install-schema.sh | 2 +- docker/tb.env | 1 + docker/tb/run-application.sh | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docker/tb-cassandra-schema/install-schema.sh b/docker/tb-cassandra-schema/install-schema.sh index 279711933c..672a345869 100644 --- a/docker/tb-cassandra-schema/install-schema.sh +++ b/docker/tb-cassandra-schema/install-schema.sh @@ -18,7 +18,7 @@ until nmap $CASSANDRA_URL -p 9042 | grep "9042/tcp open" do - echo "Wait for Cassandra..." + echo "Wait for $CASSANDRA_URL..." sleep 10 done diff --git a/docker/tb.env b/docker/tb.env index 3850e3dee9..7947c23d43 100644 --- a/docker/tb.env +++ b/docker/tb.env @@ -1,5 +1,6 @@ #Thingsboard server configuration +TB_CASSANDRA_SCHEMA_URL=tb-cassandra-schema CASSANDRA_URL=cassandra:9042 ZOOKEEPER_URL=zk:2181 MQTT_BIND_ADDRESS=0.0.0.0 diff --git a/docker/tb/run-application.sh b/docker/tb/run-application.sh index 461774cfa6..c5df758eda 100755 --- a/docker/tb/run-application.sh +++ b/docker/tb/run-application.sh @@ -21,12 +21,12 @@ dpkg -i /root/thingsboard.deb reachable=0 while [ $reachable -eq 0 ]; do - echo "tb-cassandra-schema container is still in progress. waiting until it completed..." + echo "$TB_CASSANDRA_SCHEMA_URL container is still in progress. waiting until it completed..." sleep 3 - ping -q -c 1 tb-cassandra-schema > /dev/null 2>&1 + ping -q -c 1 $TB_CASSANDRA_SCHEMA_URL > /dev/null 2>&1 if [ "$?" -ne 0 ]; then - echo "tb-cassandra-schema container completed!" + echo "$TB_CASSANDRA_SCHEMA_URL container completed!" reachable=1 fi done From 1f5aa830068315fa611385750105bc4a76b489d9 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 25 May 2017 12:49:19 +0300 Subject: [PATCH 18/21] Updates to proper namings --- docker/.env | 6 +++--- docker/docker-compose.yml | 6 +++--- docker/tb-cassandra-schema/install-schema.sh | 6 +++--- docker/tb-cassandra-schema/tb-cassandra-schema.yaml | 6 +++--- docker/zookeeper/zookeeper.yaml | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docker/.env b/docker/.env index c03637ecd5..1c7e512569 100644 --- a/docker/.env +++ b/docker/.env @@ -1,7 +1,7 @@ CASSANDRA_DATA_DIR=/home/docker/cassandra_volume # cassandra schema container environment variables -SKIP_SCHEMA_CREATION=false -SKIP_SYSTEM_DATA=true -SKIP_DEMO_DATA=true +CREATE_SCHEMA=true +ADD_SYSTEM_DATA=false +ADD_DEMO_DATA=false CASSANDRA_URL=cassandra \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index ebf1202061..8367abcd9b 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -29,9 +29,9 @@ services: tb-cassandra-schema: image: "thingsboard/tb-cassandra-schema:1.2.4" environment: - - SKIP_SCHEMA_CREATION=${SKIP_SCHEMA_CREATION} - - SKIP_SYSTEM_DATA=${SKIP_SYSTEM_DATA} - - SKIP_DEMO_DATA=${SKIP_DEMO_DATA} + - CREATE_SCHEMA=${CREATE_SCHEMA} + - ADD_SYSTEM_DATA=${ADD_SYSTEM_DATA} + - ADD_DEMO_DATA=${ADD_DEMO_DATA} - CASSANDRA_URL=${CASSANDRA_URL} entrypoint: ./install-schema.sh cassandra: diff --git a/docker/tb-cassandra-schema/install-schema.sh b/docker/tb-cassandra-schema/install-schema.sh index 672a345869..128bd16e5e 100644 --- a/docker/tb-cassandra-schema/install-schema.sh +++ b/docker/tb-cassandra-schema/install-schema.sh @@ -22,7 +22,7 @@ do sleep 10 done -if [ "$SKIP_SCHEMA_CREATION" == "false" ]; then +if [ "$CREATE_SCHEMA" == "true" ]; then echo "Creating 'Thingsboard' keyspace..." cqlsh $CASSANDRA_URL -f /root/schema.cql if [ "$?" -eq 0 ]; then @@ -32,7 +32,7 @@ if [ "$SKIP_SCHEMA_CREATION" == "false" ]; then fi fi -if [ "$SKIP_SYSTEM_DATA" == "false" ]; then +if [ "$ADD_SYSTEM_DATA" == "true" ]; then echo "Adding system data..." cqlsh $CASSANDRA_URL -f /root/system-data.cql if [ "$?" -eq 0 ]; then @@ -42,7 +42,7 @@ if [ "$SKIP_SYSTEM_DATA" == "false" ]; then fi fi -if [ "$SKIP_DEMO_DATA" == "false" ]; then +if [ "$ADD_DEMO_DATA" == "true" ]; then echo "Adding demo data..." cqlsh $CASSANDRA_URL -f /root/demo-data.cql if [ "$?" -eq 0 ]; then diff --git a/docker/tb-cassandra-schema/tb-cassandra-schema.yaml b/docker/tb-cassandra-schema/tb-cassandra-schema.yaml index e3340a438a..e1e27220d7 100644 --- a/docker/tb-cassandra-schema/tb-cassandra-schema.yaml +++ b/docker/tb-cassandra-schema/tb-cassandra-schema.yaml @@ -24,11 +24,11 @@ spec: imagePullPolicy: Always image: thingsboard/tb-cassandra-schema:1.2.4 env: - - name: SKIP_SCHEMA_CREATION + - name: CREATE_SCHEMA value: "false" - - name: SKIP_SYSTEM_DATA + - name: ADD_SYSTEM_DATA value: "false" - - name : SKIP_DEMO_DATA + - name : ADD_DEMO_DATA value: "false" - name : CASSANDRA_URL value: "cassandra-headless" diff --git a/docker/zookeeper/zookeeper.yaml b/docker/zookeeper/zookeeper.yaml index d027f8e6d5..d96a74472a 100644 --- a/docker/zookeeper/zookeeper.yaml +++ b/docker/zookeeper/zookeeper.yaml @@ -35,7 +35,7 @@ kind: ConfigMap metadata: name: zk-config data: - ensemble: "zk-0;zk-1" + ensemble: "zk-0;zk-1;zk-2" replicas: "3" jvm.heap: "500m" tick: "2000" @@ -56,7 +56,7 @@ spec: selector: matchLabels: app: zk - minAvailable: 2 + minAvailable: 3 --- apiVersion: apps/v1beta1 kind: StatefulSet @@ -64,7 +64,7 @@ metadata: name: zk spec: serviceName: zk-headless - replicas: 2 + replicas: 3 template: metadata: labels: From 8e4d704b846b4d1d2855e85d16fa27e2d1bd0f78 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 25 May 2017 14:11:13 +0300 Subject: [PATCH 19/21] Fixed cassandra labels --- docker/cassandra/cassandra.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/cassandra/cassandra.yaml b/docker/cassandra/cassandra.yaml index e54d47b07a..68379d3d45 100644 --- a/docker/cassandra/cassandra.yaml +++ b/docker/cassandra/cassandra.yaml @@ -83,11 +83,11 @@ spec: - name: CASSANDRA_SEEDS value: "cassandra-0.cassandra-headless.default.svc.cluster.local" - name: CASSANDRA_CLUSTER_NAME - value: "K8Demo" + value: "Thingsboard-Cluster" - name: CASSANDRA_DC - value: "DC1-K8Demo" + value: "DC1-Thingsboard-Cluster" - name: CASSANDRA_RACK - value: "Rack1-K8Demo" + value: "Rack-Thingsboard-Cluster" - name: CASSANDRA_AUTO_BOOTSTRAP value: "false" - name: POD_IP From 2e618ee6748a3135f10c3e4f42df95f312da2fe8 Mon Sep 17 00:00:00 2001 From: volodymyr-babak Date: Mon, 29 May 2017 10:33:33 +0300 Subject: [PATCH 20/21] Revert changes for the config parameters --- application/src/main/resources/thingsboard.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 24cea0e4af..4b488af7bb 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -66,10 +66,10 @@ plugins: # JWT Token parameters security.jwt: - token-expiration-time: "${JWT_TOKEN_EXPIRATION_TIME:9000000}" # Number of seconds (15 mins) - refresh-token-exp-time: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:36000000}" # Seconds (1 hour) - token-issuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" - token-signing-key: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}" + tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:9000000}" # Number of seconds (15 mins) + refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:36000000}" # Seconds (1 hour) + tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" + tokenSigningKey: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}" # Device communication protocol parameters http: From a708509aacbab0a723833c29b28a0775a2f6ac77 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 29 May 2017 11:47:43 +0300 Subject: [PATCH 21/21] Entity relations management. --- .../controller/EntityRelationController.java | 16 ++ .../server/common/data/Customer.java | 7 +- .../server/common/data/DashboardInfo.java | 7 +- .../server/common/data/Device.java | 3 +- .../server/common/data/HasName.java | 22 +++ .../server/common/data/Tenant.java | 7 +- .../thingsboard/server/common/data/User.java | 7 +- .../server/common/data/alarm/Alarm.java | 7 +- .../server/common/data/asset/Asset.java | 4 +- .../common/data/plugin/PluginMetaData.java | 4 +- .../common/data/relation/EntityRelation.java | 10 +- .../data/relation/EntityRelationInfo.java | 59 ++++++ .../server/common/data/rule/RuleMetaData.java | 8 +- .../server/dao/alarm/AlarmService.java | 4 + .../server/dao/alarm/BaseAlarmService.java | 66 +++++++ .../server/dao/asset/BaseAssetService.java | 4 +- .../dao/customer/CustomerServiceImpl.java | 6 +- .../dao/dashboard/DashboardService.java | 5 + .../dao/dashboard/DashboardServiceImpl.java | 24 ++- .../server/dao/device/DeviceServiceImpl.java | 4 +- .../dao/entity/AbstractEntityService.java | 36 ++++ .../server/dao/entity/BaseEntityService.java | 93 ++++++++- .../server/dao/entity/EntityService.java | 28 +++ .../server/dao/plugin/BasePluginService.java | 6 +- .../dao/relation/BaseRelationService.java | 43 +++++ .../server/dao/relation/RelationService.java | 3 + .../server/dao/rule/BaseRuleService.java | 6 +- .../server/dao/tenant/TenantServiceImpl.java | 6 +- .../server/dao/user/UserService.java | 3 + .../server/dao/user/UserServiceImpl.java | 15 +- ui/src/app/api/entity-relation.service.js | 13 ++ ui/src/app/api/entity.service.js | 113 ++++++----- ui/src/app/asset/assets.tpl.html | 6 + ui/src/app/common/types.constant.js | 5 +- ui/src/app/common/utils.service.js | 26 ++- .../dashboard-autocomplete.tpl.html | 2 +- ui/src/app/components/plugin-select.tpl.html | 2 +- .../states/entity-state-controller.js | 2 +- .../entity/attribute/attribute-table.tpl.html | 6 +- .../app/entity/entity-aliases.controller.js | 2 +- .../entity/entity-autocomplete.directive.js | 171 +++++++++++++++++ ui/src/app/entity/entity-autocomplete.scss | 25 +++ .../app/entity/entity-autocomplete.tpl.html | 45 +++++ ui/src/app/entity/entity-filter.directive.js | 8 - ui/src/app/entity/entity-filter.tpl.html | 2 +- ui/src/app/entity/entity-select.directive.js | 86 +++++++++ ui/src/app/entity/entity-select.scss | 19 ++ ui/src/app/entity/entity-select.tpl.html | 29 +++ .../entity/entity-type-select.directive.js | 19 +- ui/src/app/entity/index.js | 6 + .../add-relation-dialog.controller.js | 43 +++++ .../relation/add-relation-dialog.tpl.html | 64 +++++++ .../relation/relation-table.directive.js | 179 ++++++++++++++++++ .../app/entity/relation/relation-table.scss | 28 +++ .../entity/relation/relation-table.tpl.html | 119 ++++++++++++ ui/src/app/locale/locale.constant-es.js | 6 +- ui/src/app/locale/locale.constant-ko.js | 6 +- ui/src/app/locale/locale.constant-ru.js | 6 +- ui/src/app/locale/locale.constant-zh.js | 6 +- ui/src/app/locale/locale.constant.js | 65 ++++++- ui/src/scss/main.scss | 39 ++++ 61 files changed, 1516 insertions(+), 145 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/HasName.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/entity/EntityService.java create mode 100644 ui/src/app/entity/entity-autocomplete.directive.js create mode 100644 ui/src/app/entity/entity-autocomplete.scss create mode 100644 ui/src/app/entity/entity-autocomplete.tpl.html create mode 100644 ui/src/app/entity/entity-select.directive.js create mode 100644 ui/src/app/entity/entity-select.scss create mode 100644 ui/src/app/entity/entity-select.tpl.html create mode 100644 ui/src/app/entity/relation/add-relation-dialog.controller.js create mode 100644 ui/src/app/entity/relation/add-relation-dialog.tpl.html create mode 100644 ui/src/app/entity/relation/relation-table.directive.js create mode 100644 ui/src/app/entity/relation/relation-table.scss create mode 100644 ui/src/app/entity/relation/relation-table.tpl.html diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 0c1fd8bf73..04f1c3ffc7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.*; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.dao.relation.EntityRelationsQuery; import org.thingsboard.server.exception.ThingsboardErrorCode; import org.thingsboard.server.exception.ThingsboardException; @@ -127,6 +128,21 @@ public class EntityRelationController extends BaseController { } } + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"fromId", "fromType"}) + @ResponseBody + public List findInfoByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType) throws ThingsboardException { + checkParameter("fromId", strFromId); + checkParameter("fromType", strFromType); + EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); + checkEntityId(entityId); + try { + return checkNotNull(relationService.findInfoByFrom(entityId).get()); + } catch (Exception e) { + throw handleException(e); + } + } + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"}) @ResponseBody diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java index 71a45270b8..f8c1e3045a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java @@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.id.TenantId; import com.fasterxml.jackson.databind.JsonNode; -public class Customer extends ContactBased{ +public class Customer extends ContactBased implements HasName { private static final long serialVersionUID = -1599722990298929275L; @@ -59,6 +59,11 @@ public class Customer extends ContactBased{ this.title = title; } + @Override + public String getName() { + return title; + } + public JsonNode getAdditionalInfo() { return additionalInfo; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java index d88df160f8..c4daf9d85c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java @@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; -public class DashboardInfo extends SearchTextBased { +public class DashboardInfo extends SearchTextBased implements HasName { private TenantId tenantId; private CustomerId customerId; @@ -64,6 +64,11 @@ public class DashboardInfo extends SearchTextBased { this.title = title; } + @Override + public String getName() { + return title; + } + @Override public String getSearchText() { return title; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index 92e8655c72..7d3d4f5742 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.TenantId; import com.fasterxml.jackson.databind.JsonNode; -public class Device extends SearchTextBased { +public class Device extends SearchTextBased implements HasName { private static final long serialVersionUID = 2807343040519543363L; @@ -64,6 +64,7 @@ public class Device extends SearchTextBased { this.customerId = customerId; } + @Override public String getName() { return name; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HasName.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasName.java new file mode 100644 index 0000000000..f43198908e --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasName.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data; + +public interface HasName { + + String getName(); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java index aee1510608..3a5f6bf09a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java @@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.TenantId; import com.fasterxml.jackson.databind.JsonNode; -public class Tenant extends ContactBased{ +public class Tenant extends ContactBased implements HasName { private static final long serialVersionUID = 8057243243859922101L; @@ -50,6 +50,11 @@ public class Tenant extends ContactBased{ this.title = title; } + @Override + public String getName() { + return title; + } + public String getRegion() { return region; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/User.java b/common/data/src/main/java/org/thingsboard/server/common/data/User.java index 74fa4cff96..0543ef0a38 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/User.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/User.java @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.security.Authority; import com.fasterxml.jackson.databind.JsonNode; -public class User extends SearchTextBased { +public class User extends SearchTextBased implements HasName { private static final long serialVersionUID = 8250339805336035966L; @@ -77,6 +77,11 @@ public class User extends SearchTextBased { this.email = email; } + @Override + public String getName() { + return email; + } + public Authority getAuthority() { return authority; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java index 19d671cab2..4bef0079b3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java @@ -18,13 +18,14 @@ package org.thingsboard.server.common.data.alarm; import com.fasterxml.jackson.databind.JsonNode; import lombok.Data; import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.id.EntityId; /** * Created by ashvayka on 11.05.17. */ @Data -public class Alarm extends BaseData { +public class Alarm extends BaseData implements HasName { private long startTs; private long endTs; @@ -37,4 +38,8 @@ public class Alarm extends BaseData { private JsonNode details; private boolean propagate; + @Override + public String getName() { + return type; + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java index 2e20b7745c..dafa514f61 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java @@ -16,12 +16,13 @@ package org.thingsboard.server.common.data.asset; import com.fasterxml.jackson.databind.JsonNode; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; -public class Asset extends SearchTextBased { +public class Asset extends SearchTextBased implements HasName { private static final long serialVersionUID = 2807343040519543363L; @@ -64,6 +65,7 @@ public class Asset extends SearchTextBased { this.customerId = customerId; } + @Override public String getName() { return name; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/PluginMetaData.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/PluginMetaData.java index 5019cd119f..e5eb149fbc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/PluginMetaData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/PluginMetaData.java @@ -15,13 +15,14 @@ */ package org.thingsboard.server.common.data.plugin; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.PluginId; import org.thingsboard.server.common.data.id.TenantId; import com.fasterxml.jackson.databind.JsonNode; -public class PluginMetaData extends SearchTextBased { +public class PluginMetaData extends SearchTextBased implements HasName { private static final long serialVersionUID = 1L; @@ -75,6 +76,7 @@ public class PluginMetaData extends SearchTextBased { this.tenantId = tenantId; } + @Override public String getName() { return name; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java index 8fcf2691af..39e7d54978 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelation.java @@ -47,11 +47,11 @@ public class EntityRelation { this.additionalInfo = additionalInfo; } - public EntityRelation(EntityRelation device) { - this.from = device.getFrom(); - this.to = device.getTo(); - this.type = device.getType(); - this.additionalInfo = device.getAdditionalInfo(); + public EntityRelation(EntityRelation entityRelation) { + this.from = entityRelation.getFrom(); + this.to = entityRelation.getTo(); + this.type = entityRelation.getType(); + this.additionalInfo = entityRelation.getAdditionalInfo(); } public EntityId getFrom() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java new file mode 100644 index 0000000000..709ad7937a --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java @@ -0,0 +1,59 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thingsboard.server.common.data.relation; + +public class EntityRelationInfo extends EntityRelation { + + private static final long serialVersionUID = 2807343097519543363L; + + private String toName; + + public EntityRelationInfo() { + super(); + } + + public EntityRelationInfo(EntityRelation entityRelation) { + super(entityRelation); + } + + public String getToName() { + return toName; + } + + public void setToName(String toName) { + this.toName = toName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + EntityRelationInfo that = (EntityRelationInfo) o; + + return toName != null ? toName.equals(that.toName) : that.toName == null; + + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (toName != null ? toName.hashCode() : 0); + return result; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleMetaData.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleMetaData.java index ecbc86cd6e..8a0f847617 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleMetaData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleMetaData.java @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.rule; import lombok.Data; import lombok.ToString; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.RuleId; @@ -26,7 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode; import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; @Data -public class RuleMetaData extends SearchTextBased { +public class RuleMetaData extends SearchTextBased implements HasName { private static final long serialVersionUID = -5656679015122935465L; @@ -66,4 +67,9 @@ public class RuleMetaData extends SearchTextBased { return name; } + @Override + public String getName() { + return name; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index 35bd247602..dca229b2a5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -28,6 +28,10 @@ import java.util.Optional; */ public interface AlarmService { + Alarm findAlarmById(AlarmId alarmId); + + ListenableFuture findAlarmByIdAsync(AlarmId alarmId); + Optional saveIfNotExists(Alarm alarm); ListenableFuture updateAlarm(Alarm alarm); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java new file mode 100644 index 0000000000..5ed15b753f --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -0,0 +1,66 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.alarm; + +import com.google.common.util.concurrent.ListenableFuture; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmId; +import org.thingsboard.server.common.data.alarm.AlarmQuery; +import org.thingsboard.server.common.data.page.TimePageData; + +import java.util.Optional; + +@Service +@Slf4j +public class BaseAlarmService implements AlarmService { + + @Override + public Alarm findAlarmById(AlarmId alarmId) { + return null; + } + + @Override + public ListenableFuture findAlarmByIdAsync(AlarmId alarmId) { + return null; + } + + @Override + public Optional saveIfNotExists(Alarm alarm) { + return null; + } + + @Override + public ListenableFuture updateAlarm(Alarm alarm) { + return null; + } + + @Override + public ListenableFuture ackAlarm(Alarm alarm) { + return null; + } + + @Override + public ListenableFuture clearAlarm(AlarmId alarmId) { + return null; + } + + @Override + public ListenableFuture> findAlarms(AlarmQuery query) { + return null; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index fce0c5eefd..3a5f803046 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.dao.customer.CustomerDao; -import org.thingsboard.server.dao.entity.BaseEntityService; +import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.*; import org.thingsboard.server.dao.relation.EntitySearchDirection; @@ -55,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.*; @Service @Slf4j -public class BaseAssetService extends BaseEntityService implements AssetService { +public class BaseAssetService extends AbstractEntityService implements AssetService { @Autowired private AssetDao assetDao; diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index e9f6836774..ff726dafb2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -31,17 +31,15 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.entity.BaseEntityService; +import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; -import org.thingsboard.server.dao.model.AssetEntity; import org.thingsboard.server.dao.model.CustomerEntity; import org.thingsboard.server.dao.model.TenantEntity; import org.thingsboard.server.dao.service.DataValidator; @@ -53,7 +51,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.dao.service.Validator; @Service @Slf4j -public class CustomerServiceImpl extends BaseEntityService implements CustomerService { +public class CustomerServiceImpl extends AbstractEntityService implements CustomerService { private static final String PUBLIC_CUSTOMER_TITLE = "Public"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java index b0ebbfd5f0..f1f174eb0b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.dashboard; +import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.id.CustomerId; @@ -27,8 +28,12 @@ public interface DashboardService { public Dashboard findDashboardById(DashboardId dashboardId); + public ListenableFuture findDashboardByIdAsync(DashboardId dashboardId); + public DashboardInfo findDashboardInfoById(DashboardId dashboardId); + public ListenableFuture findDashboardInfoByIdAsync(DashboardId dashboardId); + public Dashboard saveDashboard(Dashboard dashboard); public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index cf554f3a62..fc3e176e00 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -17,9 +17,13 @@ package org.thingsboard.server.dao.dashboard; import static org.thingsboard.server.dao.DaoUtil.convertDataList; import static org.thingsboard.server.dao.DaoUtil.getData; +import static org.thingsboard.server.dao.service.Validator.validateId; import java.util.List; +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.thingsboard.server.common.data.Dashboard; @@ -30,7 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.customer.CustomerDao; -import org.thingsboard.server.dao.entity.BaseEntityService; +import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.*; import org.thingsboard.server.dao.service.DataValidator; @@ -42,7 +46,7 @@ import org.thingsboard.server.dao.service.Validator; @Service @Slf4j -public class DashboardServiceImpl extends BaseEntityService implements DashboardService { +public class DashboardServiceImpl extends AbstractEntityService implements DashboardService { @Autowired private DashboardDao dashboardDao; @@ -64,6 +68,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard return getData(dashboardEntity); } + @Override + public ListenableFuture findDashboardByIdAsync(DashboardId dashboardId) { + log.trace("Executing findDashboardByIdAsync [{}]", dashboardId); + validateId(dashboardId, "Incorrect dashboardId " + dashboardId); + ListenableFuture dashboardEntity = dashboardDao.findByIdAsync(dashboardId.getId()); + return Futures.transform(dashboardEntity, (Function) input -> getData(input)); + } + @Override public DashboardInfo findDashboardInfoById(DashboardId dashboardId) { log.trace("Executing findDashboardInfoById [{}]", dashboardId); @@ -72,6 +84,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard return getData(dashboardInfoEntity); } + @Override + public ListenableFuture findDashboardInfoByIdAsync(DashboardId dashboardId) { + log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId); + validateId(dashboardId, "Incorrect dashboardId " + dashboardId); + ListenableFuture dashboardInfoEntity = dashboardInfoDao.findByIdAsync(dashboardId.getId()); + return Futures.transform(dashboardInfoEntity, (Function) input -> getData(input)); + } + @Override public Dashboard saveDashboard(Dashboard dashboard) { log.trace("Executing saveDashboard [{}]", dashboard); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index d01f154197..99585ea76f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -37,7 +37,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.dao.customer.CustomerDao; -import org.thingsboard.server.dao.entity.BaseEntityService; +import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.CustomerEntity; import org.thingsboard.server.dao.model.DeviceEntity; @@ -58,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.*; @Service @Slf4j -public class DeviceServiceImpl extends BaseEntityService implements DeviceService { +public class DeviceServiceImpl extends AbstractEntityService implements DeviceService { @Autowired private DeviceDao deviceDao; diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java new file mode 100644 index 0000000000..ecca491070 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thingsboard.server.dao.entity; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.dao.relation.RelationService; + +@Slf4j +public abstract class AbstractEntityService { + + @Autowired + protected RelationService relationService; + + protected void deleteEntityRelations(EntityId entityId) { + log.trace("Executing deleteEntityRelations [{}]", entityId); + relationService.deleteEntityRelations(entityId); + } + + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 3c1c528193..6f9500ed3b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -15,23 +15,102 @@ */ package org.thingsboard.server.dao.entity; +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.dao.relation.RelationService; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.*; +import org.thingsboard.server.common.data.alarm.AlarmId; +import org.thingsboard.server.common.data.id.*; +import org.thingsboard.server.dao.alarm.AlarmService; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.dashboard.DashboardService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.plugin.PluginService; +import org.thingsboard.server.dao.rule.RuleService; +import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.dao.user.UserService; /** * Created by ashvayka on 04.05.17. */ +@Service @Slf4j -public class BaseEntityService { +public class BaseEntityService extends AbstractEntityService implements EntityService { @Autowired - protected RelationService relationService; + private AssetService assetService; - protected void deleteEntityRelations(EntityId entityId) { - log.trace("Executing deleteEntityRelations [{}]", entityId); - relationService.deleteEntityRelations(entityId); + @Autowired + private DeviceService deviceService; + + @Autowired + private RuleService ruleService; + + @Autowired + private PluginService pluginService; + + @Autowired + private TenantService tenantService; + + @Autowired + private CustomerService customerService; + + @Autowired + private UserService userService; + + @Autowired + private DashboardService dashboardService; + + @Autowired + private AlarmService alarmService; + + @Override + public void deleteEntityRelations(EntityId entityId) { + super.deleteEntityRelations(entityId); + } + + @Override + public ListenableFuture fetchEntityNameAsync(EntityId entityId) { + log.trace("Executing fetchEntityNameAsync [{}]", entityId); + ListenableFuture entityName; + ListenableFuture hasName; + switch (entityId.getEntityType()) { + case ASSET: + hasName = assetService.findAssetByIdAsync(new AssetId(entityId.getId())); + break; + case DEVICE: + hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId())); + break; + case RULE: + hasName = ruleService.findRuleByIdAsync(new RuleId(entityId.getId())); + break; + case PLUGIN: + hasName = pluginService.findPluginByIdAsync(new PluginId(entityId.getId())); + break; + case TENANT: + hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId())); + break; + case CUSTOMER: + hasName = customerService.findCustomerByIdAsync(new CustomerId(entityId.getId())); + break; + case USER: + hasName = userService.findUserByIdAsync(new UserId(entityId.getId())); + break; + case DASHBOARD: + hasName = dashboardService.findDashboardInfoByIdAsync(new DashboardId(entityId.getId())); + break; + case ALARM: + hasName = alarmService.findAlarmByIdAsync(new AlarmId(entityId.getId())); + break; + default: + throw new IllegalStateException("Not Implemented!"); + } + entityName = Futures.transform(hasName, (Function) hasName1 -> hasName1.getName() ); + return entityName; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/EntityService.java new file mode 100644 index 0000000000..415f5189f3 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thingsboard.server.dao.entity; + +import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.id.EntityId; + +public interface EntityService { + + ListenableFuture fetchEntityNameAsync(EntityId entityId); + + void deleteEntityRelations(EntityId entityId); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/plugin/BasePluginService.java b/dao/src/main/java/org/thingsboard/server/dao/plugin/BasePluginService.java index 5e0eb399f6..a0be00ef0d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/plugin/BasePluginService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/plugin/BasePluginService.java @@ -22,7 +22,6 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.id.PluginId; -import org.thingsboard.server.common.data.id.RuleId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; @@ -30,9 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.PluginMetaData; -import org.thingsboard.server.common.data.rule.RuleMetaData; import org.thingsboard.server.dao.component.ComponentDescriptorService; -import org.thingsboard.server.dao.entity.BaseEntityService; +import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DatabaseException; import org.thingsboard.server.dao.exception.IncorrectParameterException; @@ -55,7 +53,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; @Service @Slf4j -public class BasePluginService extends BaseEntityService implements PluginService { +public class BasePluginService extends AbstractEntityService implements PluginService { //TODO: move to a better place. public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 1b572c64ad..e7d38e5d9b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -23,9 +23,24 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntityRelationInfo; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.plugin.PluginService; +import org.thingsboard.server.dao.rule.RuleService; +import org.thingsboard.server.dao.tenant.TenantService; import javax.annotation.Nullable; import java.util.*; @@ -41,6 +56,9 @@ public class BaseRelationService implements RelationService { @Autowired private RelationDao relationDao; + @Autowired + private EntityService entityService; + @Override public ListenableFuture checkRelation(EntityId from, EntityId to, String relationType) { log.trace("Executing checkRelation [{}][{}][{}]", from, to, relationType); @@ -99,6 +117,31 @@ public class BaseRelationService implements RelationService { return relationDao.findAllByFrom(from); } + @Override + public ListenableFuture> findInfoByFrom(EntityId from) { + log.trace("Executing findInfoByFrom [{}]", from); + validate(from); + ListenableFuture> relations = relationDao.findAllByFrom(from); + ListenableFuture> relationsInfo = Futures.transform(relations, + (AsyncFunction, List>) relations1 -> { + List> futures = new ArrayList<>(); + relations1.stream().forEach(relation -> futures.add(fetchRelationInfoAsync(relation))); + return Futures.successfulAsList(futures); + }); + return relationsInfo; + } + + private ListenableFuture fetchRelationInfoAsync(EntityRelation relation) { + ListenableFuture entityName = entityService.fetchEntityNameAsync(relation.getTo()); + ListenableFuture entityRelationInfo = + Futures.transform(entityName, (Function) entityName1 -> { + EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation); + entityRelationInfo1.setToName(entityName1); + return entityRelationInfo1; + }); + return entityRelationInfo; + } + @Override public ListenableFuture> findByFromAndType(EntityId from, String relationType) { log.trace("Executing findByFromAndType [{}][{}]", from, relationType); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java index f4f3a37185..353e595865 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.relation; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntityRelationInfo; import java.util.List; @@ -38,6 +39,8 @@ public interface RelationService { ListenableFuture> findByFrom(EntityId from); + ListenableFuture> findInfoByFrom(EntityId from); + ListenableFuture> findByFromAndType(EntityId from, String relationType); ListenableFuture> findByTo(EntityId to); diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleService.java index fb5e9ce146..350fc3a7cb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleService.java @@ -23,7 +23,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.RuleId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; @@ -34,11 +33,10 @@ import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.PluginMetaData; import org.thingsboard.server.common.data.rule.RuleMetaData; import org.thingsboard.server.dao.component.ComponentDescriptorService; -import org.thingsboard.server.dao.entity.BaseEntityService; +import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DatabaseException; import org.thingsboard.server.dao.exception.IncorrectParameterException; -import org.thingsboard.server.dao.model.AssetEntity; import org.thingsboard.server.dao.model.RuleMetaDataEntity; import org.thingsboard.server.dao.plugin.PluginService; import org.thingsboard.server.dao.service.DataValidator; @@ -58,7 +56,7 @@ import static org.thingsboard.server.dao.service.Validator.validatePageLink; @Service @Slf4j -public class BaseRuleService extends BaseEntityService implements RuleService { +public class BaseRuleService extends AbstractEntityService implements RuleService { private final TenantId systemTenantId = new TenantId(NULL_UUID); diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index bcc31a835e..e6f5011124 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -26,7 +26,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; @@ -34,9 +33,8 @@ import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.entity.BaseEntityService; +import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; -import org.thingsboard.server.dao.model.CustomerEntity; import org.thingsboard.server.dao.model.TenantEntity; import org.thingsboard.server.dao.plugin.PluginService; import org.thingsboard.server.dao.rule.RuleService; @@ -50,7 +48,7 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService; @Service @Slf4j -public class TenantServiceImpl extends BaseEntityService implements TenantService { +public class TenantServiceImpl extends AbstractEntityService implements TenantService { private static final String DEFAULT_TENANT_REGION = "Global"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserService.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserService.java index f4043a0d6e..47e800cfa2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.user; +import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -27,6 +28,8 @@ public interface UserService { public User findUserById(UserId userId); + public ListenableFuture findUserByIdAsync(UserId userId); + public User findUserByEmail(String email); public User saveUser(User user); diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 64101110b4..125040b019 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -23,6 +23,9 @@ import static org.thingsboard.server.dao.service.Validator.validateString; import java.util.List; +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; @@ -35,7 +38,7 @@ import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.dao.customer.CustomerDao; -import org.thingsboard.server.dao.entity.BaseEntityService; +import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.*; @@ -47,7 +50,7 @@ import org.springframework.stereotype.Service; @Service @Slf4j -public class UserServiceImpl extends BaseEntityService implements UserService { +public class UserServiceImpl extends AbstractEntityService implements UserService { @Autowired private UserDao userDao; @@ -77,6 +80,14 @@ public class UserServiceImpl extends BaseEntityService implements UserService { return getData(userEntity); } + @Override + public ListenableFuture findUserByIdAsync(UserId userId) { + log.trace("Executing findUserByIdAsync [{}]", userId); + validateId(userId, "Incorrect userId " + userId); + ListenableFuture userEntity = userDao.findByIdAsync(userId.getId()); + return Futures.transform(userEntity, (Function) input -> getData(input)); + } + @Override public User saveUser(User user) { log.trace("Executing saveUser [{}]", user); diff --git a/ui/src/app/api/entity-relation.service.js b/ui/src/app/api/entity-relation.service.js index 998607ad65..703964594b 100644 --- a/ui/src/app/api/entity-relation.service.js +++ b/ui/src/app/api/entity-relation.service.js @@ -25,6 +25,7 @@ function EntityRelationService($http, $q) { deleteRelation: deleteRelation, deleteRelations: deleteRelations, findByFrom: findByFrom, + findInfoByFrom: findInfoByFrom, findByFromAndType: findByFromAndType, findByTo: findByTo, findByToAndType: findByToAndType, @@ -84,6 +85,18 @@ function EntityRelationService($http, $q) { return deferred.promise; } + function findInfoByFrom(fromId, fromType) { + var deferred = $q.defer(); + var url = '/api/relations/info?fromId=' + fromId; + url += '&fromType=' + fromType; + $http.get(url, null).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + function findByFromAndType(fromId, fromType, relationType) { var deferred = $q.defer(); var url = '/api/relations?fromId=' + fromId; diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index a70308b52f..891f9d83b2 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -20,14 +20,13 @@ export default angular.module('thingsboard.api.entity', [thingsboardTypes]) .name; /*@ngInject*/ -function EntityService($http, $q, $filter, $translate, userService, deviceService, +function EntityService($http, $q, $filter, $translate, $log, userService, deviceService, assetService, tenantService, customerService, - ruleService, pluginService, entityRelationService, attributeService, types, utils) { + ruleService, pluginService, dashboardService, entityRelationService, attributeService, types, utils) { var service = { getEntity: getEntity, getEntities: getEntities, getEntitiesByNameFilter: getEntitiesByNameFilter, - entityName: entityName, processEntityAliases: processEntityAliases, getEntityKeys: getEntityKeys, checkEntityAlias: checkEntityAlias, @@ -63,6 +62,15 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic case types.entityType.plugin: promise = pluginService.getPlugin(entityId); break; + case types.entityType.dashboard: + promise = dashboardService.getDashboardInfo(entityId); + break; + case types.entityType.user: + promise = userService.getUser(entityId); + break; + case types.entityType.alarm: + $log.error('Get Alarm Entity is not implemented!'); + break; } return promise; } @@ -134,6 +142,15 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic case types.entityType.plugin: promise = getEntitiesByIdsPromise(pluginService.getPlugin, entityIds); break; + case types.entityType.dashboard: + promise = getEntitiesByIdsPromise(dashboardService.getDashboardInfo, entityIds); + break; + case types.entityType.user: + promise = getEntitiesByIdsPromise(userService.getUser, entityIds); + break; + case types.entityType.alarm: + $log.error('Get Alarm Entity is not implemented!'); + break; } return promise; } @@ -141,34 +158,38 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic function getEntities(entityType, entityIds, config) { var deferred = $q.defer(); var promise = getEntitiesPromise(entityType, entityIds, config); - promise.then( - function success(result) { - deferred.resolve(result); - }, - function fail() { - deferred.reject(); - } - ); + if (promise) { + promise.then( + function success(result) { + deferred.resolve(result); + }, + function fail() { + deferred.reject(); + } + ); + } else { + deferred.reject(); + } return deferred.promise; } - function getEntitiesByPageLinkPromise(entityType, pageLink, config) { + function getEntitiesByPageLinkPromise(entityType, pageLink, config, subType) { var promise; var user = userService.getCurrentUser(); var customerId = user.customerId; switch (entityType) { case types.entityType.device: if (user.authority === 'CUSTOMER_USER') { - promise = deviceService.getCustomerDevices(customerId, pageLink, false, config); + promise = deviceService.getCustomerDevices(customerId, pageLink, false, config, subType); } else { - promise = deviceService.getTenantDevices(pageLink, false, config); + promise = deviceService.getTenantDevices(pageLink, false, config, subType); } break; case types.entityType.asset: if (user.authority === 'CUSTOMER_USER') { - promise = assetService.getCustomerAssets(customerId, pageLink, false, config); + promise = assetService.getCustomerAssets(customerId, pageLink, false, config, subType); } else { - promise = assetService.getTenantAssets(pageLink, false, config); + promise = assetService.getTenantAssets(pageLink, false, config, subType); } break; case types.entityType.tenant: @@ -183,48 +204,48 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic case types.entityType.plugin: promise = pluginService.getAllPlugins(pageLink); break; + case types.entityType.dashboard: + if (user.authority === 'CUSTOMER_USER') { + promise = dashboardService.getCustomerDashboards(customerId, pageLink); + } else { + promise = dashboardService.getTenantDashboards(pageLink); + } + break; + case types.entityType.user: + $log.error('Get User Entities is not implemented!'); + break; + case types.entityType.alarm: + $log.error('Get Alarm Entities is not implemented!'); + break; } return promise; } - function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config) { + function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config, subType) { var deferred = $q.defer(); var pageLink = {limit: limit, textSearch: entityNameFilter}; - var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config); - promise.then( - function success(result) { - if (result.data && result.data.length > 0) { - deferred.resolve(result.data); - } else { + var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config, subType); + if (promise) { + promise.then( + function success(result) { + if (result.data && result.data.length > 0) { + deferred.resolve(result.data); + } else { + deferred.resolve(null); + } + }, + function fail() { deferred.resolve(null); } - }, - function fail() { - deferred.resolve(null); - } - ); - return deferred.promise; - } - - function entityName(entityType, entity) { - var name = ''; - switch (entityType) { - case types.entityType.device: - case types.entityType.asset: - case types.entityType.rule: - case types.entityType.plugin: - name = entity.name; - break; - case types.entityType.tenant: - case types.entityType.customer: - name = entity.title; - break; + ); + } else { + deferred.resolve(null); } - return name; + return deferred.promise; } function entityToEntityInfo(entityType, entity) { - return { name: entityName(entityType, entity), entityType: entityType, id: entity.id.id }; + return { name: entity.name, entityType: entityType, id: entity.id.id }; } function entitiesToEntitiesInfo(entityType, entities) { diff --git a/ui/src/app/asset/assets.tpl.html b/ui/src/app/asset/assets.tpl.html index fb3cf56c86..11a118f5e4 100644 --- a/ui/src/app/asset/assets.tpl.html +++ b/ui/src/app/asset/assets.tpl.html @@ -55,4 +55,10 @@ default-event-type="{{vm.types.eventType.alarm.value}}"> + + + + diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index a8d8556f38..47ac7a01ed 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -98,7 +98,10 @@ export default angular.module('thingsboard.types', []) rule: "RULE", plugin: "PLUGIN", tenant: "TENANT", - customer: "CUSTOMER" + customer: "CUSTOMER", + user: "USER", + dashboard: "DASHBOARD", + alarm: "ALARM" }, entitySearchDirection: { from: "FROM", diff --git a/ui/src/app/common/utils.service.js b/ui/src/app/common/utils.service.js index b324cbfa45..7b4d65ef78 100644 --- a/ui/src/app/common/utils.service.js +++ b/ui/src/app/common/utils.service.js @@ -108,7 +108,8 @@ function Utils($mdColorPalette, $rootScope, $window, types) { guid: guid, isLocalUrl: isLocalUrl, validateDatasources: validateDatasources, - createKey: createKey + createKey: createKey, + entityTypeName: entityTypeName } return service; @@ -346,4 +347,27 @@ function Utils($mdColorPalette, $rootScope, $window, types) { return dataKey; } + function entityTypeName (type) { + switch (type) { + case types.entityType.device: + return 'entity.type-device'; + case types.entityType.asset: + return 'entity.type-asset'; + case types.entityType.rule: + return 'entity.type-rule'; + case types.entityType.plugin: + return 'entity.type-plugin'; + case types.entityType.tenant: + return 'entity.type-tenant'; + case types.entityType.customer: + return 'entity.type-customer'; + case types.entityType.user: + return 'entity.type-user'; + case types.entityType.dashboard: + return 'entity.type-dashboard'; + case types.entityType.alarm: + return 'entity.type-alarm'; + } + } + } diff --git a/ui/src/app/components/dashboard-autocomplete.tpl.html b/ui/src/app/components/dashboard-autocomplete.tpl.html index 8b6be20778..d1193c20ea 100644 --- a/ui/src/app/components/dashboard-autocomplete.tpl.html +++ b/ui/src/app/components/dashboard-autocomplete.tpl.html @@ -34,7 +34,7 @@
- dashboard.no-dashboards-matching + dashboard.no-dashboards-matching
diff --git a/ui/src/app/components/plugin-select.tpl.html b/ui/src/app/components/plugin-select.tpl.html index 420442ef4c..9a46d7f1cc 100644 --- a/ui/src/app/components/plugin-select.tpl.html +++ b/ui/src/app/components/plugin-select.tpl.html @@ -34,7 +34,7 @@
- plugin.no-plugins-matching + plugin.no-plugins-matching
diff --git a/ui/src/app/dashboard/states/entity-state-controller.js b/ui/src/app/dashboard/states/entity-state-controller.js index 3eaf453c33..8ee9285b5f 100644 --- a/ui/src/app/dashboard/states/entity-state-controller.js +++ b/ui/src/app/dashboard/states/entity-state-controller.js @@ -109,7 +109,7 @@ export default function EntityStateController($scope, $location, $state, $stateP if (params && params.entityId && params.entityId.id && params.entityId.entityType) { entityService.getEntity(params.entityId.entityType, params.entityId.id, {ignoreLoading: true, ignoreErrors: true}).then( function success(entity) { - var entityName = entityService.entityName(params.entityId.entityType, entity); + var entityName = entity.name; deferred.resolve(entityName); }, function fail() { diff --git a/ui/src/app/entity/attribute/attribute-table.tpl.html b/ui/src/app/entity/attribute/attribute-table.tpl.html index 3b10902242..1afd1bb452 100644 --- a/ui/src/app/entity/attribute/attribute-table.tpl.html +++ b/ui/src/app/entity/attribute/attribute-table.tpl.html @@ -128,9 +128,9 @@ - - - + + + diff --git a/ui/src/app/entity/entity-aliases.controller.js b/ui/src/app/entity/entity-aliases.controller.js index 4eb1737c0a..f1e2e38f6a 100644 --- a/ui/src/app/entity/entity-aliases.controller.js +++ b/ui/src/app/entity/entity-aliases.controller.js @@ -110,7 +110,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc entityAlias.changed = false; } if (!entityAlias.changed && entity && entityAlias.entityType) { - entityAlias.alias = entityService.entityName(entityAlias.entityType, entity); + entityAlias.alias = entity.name; } } } diff --git a/ui/src/app/entity/entity-autocomplete.directive.js b/ui/src/app/entity/entity-autocomplete.directive.js new file mode 100644 index 0000000000..350bde9b3e --- /dev/null +++ b/ui/src/app/entity/entity-autocomplete.directive.js @@ -0,0 +1,171 @@ +/* + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import './entity-autocomplete.scss'; + +/* eslint-disable import/no-unresolved, import/default */ + +import entityAutocompleteTemplate from './entity-autocomplete.tpl.html'; + +/* eslint-enable import/no-unresolved, import/default */ + +/*@ngInject*/ +export default function EntityAutocomplete($compile, $templateCache, $q, $filter, entityService, types) { + + var linker = function (scope, element, attrs, ngModelCtrl) { + var template = $templateCache.get(entityAutocompleteTemplate); + element.html(template); + + scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false; + scope.entity = null; + scope.entitySearchText = ''; + + scope.fetchEntities = function(searchText) { + var deferred = $q.defer(); + entityService.getEntitiesByNameFilter(scope.entityType, searchText, 50, null, scope.entitySubtype).then(function success(result) { + if (result) { + deferred.resolve(result); + } else { + deferred.resolve([]); + } + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + scope.entitySearchTextChanged = function() { + } + + scope.updateView = function () { + if (!scope.disabled) { + ngModelCtrl.$setViewValue(scope.entity ? scope.entity.id.id : null); + } + } + + ngModelCtrl.$render = function () { + if (ngModelCtrl.$viewValue) { + entityService.getEntity(scope.entityType, ngModelCtrl.$viewValue).then( + function success(entity) { + scope.entity = entity; + }, + function fail() { + scope.entity = null; + } + ); + } else { + scope.entity = null; + } + } + + scope.$watch('entityType', function () { + load(); + }); + + scope.$watch('entitySubtype', function () { + if (scope.entity && scope.entity.type != scope.entitySubtype) { + scope.entity = null; + scope.updateView(); + } + }); + + scope.$watch('entity', function () { + scope.updateView(); + }); + + scope.$watch('disabled', function () { + scope.updateView(); + }); + + + function load() { + switch (scope.entityType) { + case types.entityType.asset: + scope.selectEntityText = 'asset.select-asset'; + scope.entityText = 'asset.asset'; + scope.noEntitiesMatchingText = 'asset.no-assets-matching'; + scope.entityRequiredText = 'asset.asset-required' + break; + case types.entityType.device: + scope.selectEntityText = 'device.select-device'; + scope.entityText = 'device.device'; + scope.noEntitiesMatchingText = 'device.no-devices-matching'; + scope.entityRequiredText = 'device.device-required' + break; + case types.entityType.rule: + scope.selectEntityText = 'rule.select-rule'; + scope.entityText = 'rule.rule'; + scope.noEntitiesMatchingText = 'rule.no-rules-matching'; + scope.entityRequiredText = 'rule.rule-required' + break; + case types.entityType.plugin: + scope.selectEntityText = 'plugin.select-plugin'; + scope.entityText = 'plugin.plugin'; + scope.noEntitiesMatchingText = 'plugin.no-plugins-matching'; + scope.entityRequiredText = 'plugin.plugin-required' + break; + case types.entityType.tenant: + scope.selectEntityText = 'tenant.select-tenant'; + scope.entityText = 'tenant.tenant'; + scope.noEntitiesMatchingText = 'tenant.no-tenants-matching'; + scope.entityRequiredText = 'tenant.tenant-required' + break; + case types.entityType.customer: + scope.selectEntityText = 'customer.select-customer'; + scope.entityText = 'customer.customer'; + scope.noEntitiesMatchingText = 'customer.no-customers-matching'; + scope.entityRequiredText = 'customer.customer-required' + break; + case types.entityType.user: + scope.selectEntityText = 'user.select-user'; + scope.entityText = 'user.user'; + scope.noEntitiesMatchingText = 'user.no-users-matching'; + scope.entityRequiredText = 'user.user-required' + break; + case types.entityType.dashboard: + scope.selectEntityText = 'dashboard.select-dashboard'; + scope.entityText = 'dashboard.dashboard'; + scope.noEntitiesMatchingText = 'dashboard.no-dashboards-matching'; + scope.entityRequiredText = 'dashboard.dashboard-required' + break; + case types.entityType.alarm: + scope.selectEntityText = 'alarm.select-alarm'; + scope.entityText = 'alarm.alarm'; + scope.noEntitiesMatchingText = 'alarm.no-alarms-matching'; + scope.entityRequiredText = 'alarm.alarm-required' + break; + } + if (scope.entity && scope.entity.id.entityType != scope.entityType) { + scope.entity = null; + scope.updateView(); + } + } + + $compile(element.contents())(scope); + } + + return { + restrict: "E", + require: "^ngModel", + link: linker, + scope: { + theForm: '=?', + tbRequired: '=?', + disabled:'=ngDisabled', + entityType: '=', + entitySubtype: '=?' + } + }; +} diff --git a/ui/src/app/entity/entity-autocomplete.scss b/ui/src/app/entity/entity-autocomplete.scss new file mode 100644 index 0000000000..c6affa5c19 --- /dev/null +++ b/ui/src/app/entity/entity-autocomplete.scss @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.tb-entity-autocomplete { + .tb-entity-item { + display: block; + height: 48px; + } + li { + height: auto !important; + white-space: normal !important; + } +} diff --git a/ui/src/app/entity/entity-autocomplete.tpl.html b/ui/src/app/entity/entity-autocomplete.tpl.html new file mode 100644 index 0000000000..ca6f37bcc3 --- /dev/null +++ b/ui/src/app/entity/entity-autocomplete.tpl.html @@ -0,0 +1,45 @@ + + + +
+ {{item.name}} +
+
+ +
+ {{ noEntitiesMatchingText }} +
+
+
+
{{ entityRequiredText }}
+
+
diff --git a/ui/src/app/entity/entity-filter.directive.js b/ui/src/app/entity/entity-filter.directive.js index 777dbb8996..b1d92c6cc2 100644 --- a/ui/src/app/entity/entity-filter.directive.js +++ b/ui/src/app/entity/entity-filter.directive.js @@ -32,14 +32,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti scope.ngModelCtrl = ngModelCtrl; - scope.itemName = function(item) { - if (item) { - return entityService.entityName(scope.entityType, item); - } else { - return ''; - } - } - scope.fetchEntities = function(searchText, limit) { var deferred = $q.defer(); entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then(function success(result) { diff --git a/ui/src/app/entity/entity-filter.tpl.html b/ui/src/app/entity/entity-filter.tpl.html index 508e4ba42f..cbb997e40b 100644 --- a/ui/src/app/entity/entity-filter.tpl.html +++ b/ui/src/app/entity/entity-filter.tpl.html @@ -33,7 +33,7 @@ md-min-length="0" placeholder="{{ 'entity.entity-list' | translate }}"> - {{itemName(item)}} + {{item.name}} entity.no-entities-matching diff --git a/ui/src/app/entity/entity-select.directive.js b/ui/src/app/entity/entity-select.directive.js new file mode 100644 index 0000000000..8988aaeccd --- /dev/null +++ b/ui/src/app/entity/entity-select.directive.js @@ -0,0 +1,86 @@ +/* + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import './entity-select.scss'; + +/* eslint-disable import/no-unresolved, import/default */ + +import entitySelectTemplate from './entity-select.tpl.html'; + +/* eslint-enable import/no-unresolved, import/default */ + +/*@ngInject*/ +export default function EntitySelect($compile, $templateCache) { + + var linker = function (scope, element, attrs, ngModelCtrl) { + var template = $templateCache.get(entitySelectTemplate); + element.html(template); + + scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false; + scope.model = null; + + scope.updateView = function () { + if (!scope.disabled) { + var value = ngModelCtrl.$viewValue; + if (scope.model && scope.model.entityType && scope.model.entityId) { + if (!value) { + value = {}; + } + value.entityType = scope.model.entityType; + value.id = scope.model.entityId; + ngModelCtrl.$setViewValue(value); + } else { + ngModelCtrl.$setViewValue(null); + } + } + } + + ngModelCtrl.$render = function () { + if (ngModelCtrl.$viewValue) { + var value = ngModelCtrl.$viewValue; + scope.model = {}; + scope.model.entityType = value.entityType; + scope.model.entityId = value.id; + } else { + scope.model = null; + } + } + + scope.$watch('model.entityType', function () { + scope.updateView(); + }); + + scope.$watch('model.entityId', function () { + scope.updateView(); + }); + + scope.$watch('disabled', function () { + scope.updateView(); + }); + + $compile(element.contents())(scope); + } + + return { + restrict: "E", + require: "^ngModel", + link: linker, + scope: { + theForm: '=?', + tbRequired: '=?', + disabled:'=ngDisabled' + } + }; +} diff --git a/ui/src/app/entity/entity-select.scss b/ui/src/app/entity/entity-select.scss new file mode 100644 index 0000000000..166c5193fb --- /dev/null +++ b/ui/src/app/entity/entity-select.scss @@ -0,0 +1,19 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.tb-entity-select { + +} \ No newline at end of file diff --git a/ui/src/app/entity/entity-select.tpl.html b/ui/src/app/entity/entity-select.tpl.html new file mode 100644 index 0000000000..a354b1dcf6 --- /dev/null +++ b/ui/src/app/entity/entity-select.tpl.html @@ -0,0 +1,29 @@ + +
+ + + + +
\ No newline at end of file diff --git a/ui/src/app/entity/entity-type-select.directive.js b/ui/src/app/entity/entity-type-select.directive.js index 6a5a0457d6..3a595a33ff 100644 --- a/ui/src/app/entity/entity-type-select.directive.js +++ b/ui/src/app/entity/entity-type-select.directive.js @@ -23,7 +23,7 @@ import entityTypeSelectTemplate from './entity-type-select.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ /*@ngInject*/ -export default function EntityTypeSelect($compile, $templateCache, userService, types) { +export default function EntityTypeSelect($compile, $templateCache, utils, userService, types) { var linker = function (scope, element, attrs, ngModelCtrl) { var template = $templateCache.get(entityTypeSelectTemplate); @@ -51,10 +51,12 @@ export default function EntityTypeSelect($compile, $templateCache, userService, scope.entityTypes.customer = types.entityType.customer; scope.entityTypes.rule = types.entityType.rule; scope.entityTypes.plugin = types.entityType.plugin; + scope.entityTypes.dashboard = types.entityType.dashboard; break; case 'CUSTOMER_USER': scope.entityTypes.device = types.entityType.device; scope.entityTypes.asset = types.entityType.asset; + scope.entityTypes.dashboard = types.entityType.dashboard; break; } @@ -67,20 +69,7 @@ export default function EntityTypeSelect($compile, $templateCache, userService, } scope.typeName = function(type) { - switch (type) { - case types.entityType.device: - return 'entity.type-device'; - case types.entityType.asset: - return 'entity.type-asset'; - case types.entityType.rule: - return 'entity.type-rule'; - case types.entityType.plugin: - return 'entity.type-plugin'; - case types.entityType.tenant: - return 'entity.type-tenant'; - case types.entityType.customer: - return 'entity.type-customer'; - } + return utils.entityTypeName(type); } scope.updateValidity = function () { diff --git a/ui/src/app/entity/index.js b/ui/src/app/entity/index.js index 8423f11c3c..bed956208e 100644 --- a/ui/src/app/entity/index.js +++ b/ui/src/app/entity/index.js @@ -18,12 +18,15 @@ import EntityAliasesController from './entity-aliases.controller'; import EntityTypeSelectDirective from './entity-type-select.directive'; import EntitySubtypeSelectDirective from './entity-subtype-select.directive'; import EntitySubtypeAutocompleteDirective from './entity-subtype-autocomplete.directive'; +import EntityAutocompleteDirective from './entity-autocomplete.directive'; +import EntitySelectDirective from './entity-select.directive'; import EntityFilterDirective from './entity-filter.directive'; import AliasesEntitySelectPanelController from './aliases-entity-select-panel.controller'; import AliasesEntitySelectDirective from './aliases-entity-select.directive'; import AddAttributeDialogController from './attribute/add-attribute-dialog.controller'; import AddWidgetToDashboardDialogController from './attribute/add-widget-to-dashboard-dialog.controller'; import AttributeTableDirective from './attribute/attribute-table.directive'; +import RelationTableDirective from './relation/relation-table.directive'; export default angular.module('thingsboard.entity', []) .controller('EntityAliasesController', EntityAliasesController) @@ -33,7 +36,10 @@ export default angular.module('thingsboard.entity', []) .directive('tbEntityTypeSelect', EntityTypeSelectDirective) .directive('tbEntitySubtypeSelect', EntitySubtypeSelectDirective) .directive('tbEntitySubtypeAutocomplete', EntitySubtypeAutocompleteDirective) + .directive('tbEntityAutocomplete', EntityAutocompleteDirective) + .directive('tbEntitySelect', EntitySelectDirective) .directive('tbEntityFilter', EntityFilterDirective) .directive('tbAliasesEntitySelect', AliasesEntitySelectDirective) .directive('tbAttributeTable', AttributeTableDirective) + .directive('tbRelationTable', RelationTableDirective) .name; diff --git a/ui/src/app/entity/relation/add-relation-dialog.controller.js b/ui/src/app/entity/relation/add-relation-dialog.controller.js new file mode 100644 index 0000000000..c331946f7f --- /dev/null +++ b/ui/src/app/entity/relation/add-relation-dialog.controller.js @@ -0,0 +1,43 @@ +/* + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*@ngInject*/ +export default function AddRelationDialogController($scope, $mdDialog, types, entityRelationService, from) { + + var vm = this; + + vm.types = types; + + vm.relation = {}; + vm.relation.from = from; + vm.relation.type = types.entityRelationType.contains; + + vm.add = add; + vm.cancel = cancel; + + function cancel() { + $mdDialog.cancel(); + } + + function add() { + $scope.theForm.$setPristine(); + entityRelationService.saveRelation(vm.relation).then( + function success() { + $mdDialog.hide(); + } + ); + } + +} diff --git a/ui/src/app/entity/relation/add-relation-dialog.tpl.html b/ui/src/app/entity/relation/add-relation-dialog.tpl.html new file mode 100644 index 0000000000..b32d23a249 --- /dev/null +++ b/ui/src/app/entity/relation/add-relation-dialog.tpl.html @@ -0,0 +1,64 @@ + + +
+ +
+

relation.add

+ + + + +
+
+ + + +
+ +
+ + + + + {{('relation.relation-types.' + type) | translate}} + + + + {{'entity.entity' | translate }} + + +
+
+
+
+ + + + {{ 'action.add' | translate }} + + {{ 'action.cancel' | + translate }} + + + +
diff --git a/ui/src/app/entity/relation/relation-table.directive.js b/ui/src/app/entity/relation/relation-table.directive.js new file mode 100644 index 0000000000..bf4aa52ebe --- /dev/null +++ b/ui/src/app/entity/relation/relation-table.directive.js @@ -0,0 +1,179 @@ +/* + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import 'angular-material-data-table/dist/md-data-table.min.css'; +import './relation-table.scss'; + +/* eslint-disable import/no-unresolved, import/default */ + +import relationTableTemplate from './relation-table.tpl.html'; +import addRelationTemplate from './add-relation-dialog.tpl.html'; + +/* eslint-enable import/no-unresolved, import/default */ + +import AddRelationController from './add-relation-dialog.controller'; + +/*@ngInject*/ +export default function RelationTable() { + return { + restrict: "E", + scope: true, + bindToController: { + entityId: '=', + entityType: '@' + }, + controller: RelationTableController, + controllerAs: 'vm', + templateUrl: relationTableTemplate + }; +} + +/*@ngInject*/ +function RelationTableController($scope, $q, $mdDialog, $document, $translate, $filter, utils, types, entityRelationService) { + + let vm = this; + + vm.relations = []; + vm.relationsCount = 0; + vm.allRelations = []; + vm.selectedRelations = []; + + vm.query = { + order: 'typeName', + limit: 5, + page: 1, + search: null + }; + + vm.enterFilterMode = enterFilterMode; + vm.exitFilterMode = exitFilterMode; + vm.onReorder = onReorder; + vm.onPaginate = onPaginate; + vm.addRelation = addRelation; + vm.editRelation = editRelation; + vm.deleteRelation = deleteRelation; + vm.deleteRelations = deleteRelations; + vm.reloadRelations = reloadRelations; + vm.updateRelations = updateRelations; + + + $scope.$watch("vm.entityId", function(newVal, prevVal) { + if (newVal && !angular.equals(newVal, prevVal)) { + reloadRelations(); + } + }); + + $scope.$watch("vm.query.search", function(newVal, prevVal) { + if (!angular.equals(newVal, prevVal) && vm.query.search != null) { + updateRelations(); + } + }); + + function enterFilterMode () { + vm.query.search = ''; + } + + function exitFilterMode () { + vm.query.search = null; + updateRelations(); + } + + function onReorder () { + updateRelations(); + } + + function onPaginate () { + updateRelations(); + } + + function addRelation($event) { + if ($event) { + $event.stopPropagation(); + } + var from = { + id: vm.entityId, + entityType: vm.entityType + }; + $mdDialog.show({ + controller: AddRelationController, + controllerAs: 'vm', + templateUrl: addRelationTemplate, + parent: angular.element($document[0].body), + locals: { from: from }, + fullscreen: true, + targetEvent: $event + }).then(function () { + reloadRelations(); + }, function () { + }); + } + + function editRelation($event, /*relation*/) { + if ($event) { + $event.stopPropagation(); + } + //TODO: + } + + function deleteRelation($event, /*relation*/) { + if ($event) { + $event.stopPropagation(); + } + //TODO: + } + + function deleteRelations($event) { + if ($event) { + $event.stopPropagation(); + } + //TODO: + } + + function reloadRelations () { + vm.allRelations.length = 0; + vm.relations.length = 0; + vm.relationsPromise = entityRelationService.findInfoByFrom(vm.entityId, vm.entityType); + vm.relationsPromise.then( + function success(allRelations) { + allRelations.forEach(function(relation) { + relation.typeName = $translate.instant('relation.relation-type.' + relation.type); + relation.toEntityTypeName = $translate.instant(utils.entityTypeName(relation.to.entityType)); + }); + vm.allRelations = allRelations; + vm.selectedRelations = []; + vm.updateRelations(); + vm.relationsPromise = null; + }, + function fail() { + vm.allRelations = []; + vm.selectedRelations = []; + vm.updateRelations(); + vm.relationsPromise = null; + } + ) + } + + function updateRelations () { + vm.selectedRelations = []; + var result = $filter('orderBy')(vm.allRelations, vm.query.order); + if (vm.query.search != null) { + result = $filter('filter')(result, {$: vm.query.search}); + } + vm.relationsCount = result.length; + var startIndex = vm.query.limit * (vm.query.page - 1); + vm.relations = result.slice(startIndex, startIndex + vm.query.limit); + } + +} diff --git a/ui/src/app/entity/relation/relation-table.scss b/ui/src/app/entity/relation/relation-table.scss new file mode 100644 index 0000000000..f5df1fc3f6 --- /dev/null +++ b/ui/src/app/entity/relation/relation-table.scss @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import '../../../scss/constants'; + +$md-light: rgba(255, 255, 255, 100%); + +.tb-relation-table { + md-toolbar.md-table-toolbar.alternate { + .md-toolbar-tools { + md-icon { + color: $md-light; + } + } + } +} diff --git a/ui/src/app/entity/relation/relation-table.tpl.html b/ui/src/app/entity/relation/relation-table.tpl.html new file mode 100644 index 0000000000..dc0df57965 --- /dev/null +++ b/ui/src/app/entity/relation/relation-table.tpl.html @@ -0,0 +1,119 @@ + + +
+ +
+ relation.entity-relations + + + add + + {{ 'action.add' | translate }} + + + + search + + {{ 'action.search' | translate }} + + + + refresh + + {{ 'action.refresh' | translate }} + + +
+
+ +
+ + search + + {{ 'action.search' | translate }} + + + + + + + + close + + {{ 'action.close' | translate }} + + +
+
+ +
+ relation.selected-relations + + + delete + + {{ 'action.delete' | translate }} + + +
+
+ +
Last update timeKeyValueattribute.last-update-timeattribute.keyattribute.value
+ + + + + + + + + + + + + + + + +
relation.typerelation.to-entity-typerelation.to-entity-name 
{{ relation.typeName }}{{ relation.toEntityTypeName }}{{ relation.toName }} + + edit + + {{ 'relation.edit' | translate }} + + + + delete + + {{ 'relation.delete' | translate }} + + +
+ + + +
+ diff --git a/ui/src/app/locale/locale.constant-es.js b/ui/src/app/locale/locale.constant-es.js index 153019d44c..e4d4b49e53 100644 --- a/ui/src/app/locale/locale.constant-es.js +++ b/ui/src/app/locale/locale.constant-es.js @@ -235,7 +235,7 @@ "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard", "select-dashboard": "Seleccionar panel", - "no-dashboards-matching": "Panel '{{dashboard}}' no encontrado.", + "no-dashboards-matching": "Panel '{{entity}}' no encontrado.", "dashboard-required": "Panel requerido.", "select-existing": "Seleccionar paneles existentes", "create-new": "Crear nuevo panel", @@ -330,7 +330,7 @@ "create-new-key": "Crear nueva clave!", "duplicate-alias-error": "Alias duplicado '{{alias}}'.
El alias de los dispositivos deben ser únicos dentro del panel.", "configure-alias": "Configurar alias '{{alias}}'", - "no-devices-matching": "No se encontró dispositivo '{{device}}'", + "no-devices-matching": "No se encontró dispositivo '{{entity}}'", "alias": "Alias", "alias-required": "Alias de dispositivo requerido.", "remove-alias": "Eliminar alias", @@ -529,7 +529,7 @@ "system": "Sistema", "select-plugin": "plugin", "plugin": "Plugin", - "no-plugins-matching": "No se encontraron plugins: '{{plugin}}'", + "no-plugins-matching": "No se encontraron plugins: '{{entity}}'", "plugin-required": "Plugin requerido.", "plugin-require-match": "Por favor, elija un plugin existente.", "events": "Eventos", diff --git a/ui/src/app/locale/locale.constant-ko.js b/ui/src/app/locale/locale.constant-ko.js index 8b2d4bacb7..32dbf49c4a 100644 --- a/ui/src/app/locale/locale.constant-ko.js +++ b/ui/src/app/locale/locale.constant-ko.js @@ -218,7 +218,7 @@ export default function addLocaleKorean(locales) { "unassign-dashboards-title": "{ count, select, 1 {대시보드 1개} other {대시보드 #개} }의 할당을 취소하시겠습니까?", "unassign-dashboards-text": "선택된 대시보드가 할당 해제되고 커스터머는 액세스 할 수 없게됩니다.", "select-dashboard": "대시보드 선택", - "no-dashboards-matching": "'{{dashboard}}'와 일치하는 대시보드가 없습니다.", + "no-dashboards-matching": "'{{entity}}'와 일치하는 대시보드가 없습니다.", "dashboard-required": "대시보드를 입력하세요.", "select-existing": "기존 대시보드 선택", "create-new": "대시보드 생성", @@ -305,7 +305,7 @@ export default function addLocaleKorean(locales) { "create-new-key": "새로 만들기!", "duplicate-alias-error": "중복된 '{{alias}}' 앨리어스가 있습니다.
디바이스 앨리어스는 대시보드 내에서 고유해야 합니다.", "configure-alias": "'{{alias}}' 앨리어스 구성", - "no-devices-matching": "'{{device}}'와 일치하는 디바이스를 찾을 수 없습니다.", + "no-devices-matching": "'{{entity}}'와 일치하는 디바이스를 찾을 수 없습니다.", "alias": "앨리어스", "alias-required": "디바이스 앨리어스를 입력하세요.", "remove-alias": "디바이스 앨리어스 삭제", @@ -496,7 +496,7 @@ export default function addLocaleKorean(locales) { "system": "시스템", "select-plugin": "플러그인 선택", "plugin": "플러그인", - "no-plugins-matching": "'{{plugin}}'과 일치하는 플러그인을 찾을 수 없습니다.", + "no-plugins-matching": "'{{entity}}'과 일치하는 플러그인을 찾을 수 없습니다.", "plugin-required": "플러그인을 입력하세요.", "plugin-require-match": "기존의 플러그인을 선택해주세요.", "events": "이벤트", diff --git a/ui/src/app/locale/locale.constant-ru.js b/ui/src/app/locale/locale.constant-ru.js index 47c9460bbd..d7734b46d7 100644 --- a/ui/src/app/locale/locale.constant-ru.js +++ b/ui/src/app/locale/locale.constant-ru.js @@ -235,7 +235,7 @@ export default function addLocaleRussian(locales) { "socialshare-text": "'{{dashboardTitle}}' сделано ThingsBoard", "socialshare-title": "'{{dashboardTitle}}' сделано ThingsBoard", "select-dashboard": "Выберите дашборд", - "no-dashboards-matching": "Дашборд '{{dashboard}}' не найден.", + "no-dashboards-matching": "Дашборд '{{entity}}' не найден.", "dashboard-required": "Дашборд обязателен.", "select-existing": "Выберите существующий дашборд", "create-new": "Создать новый дашборд", @@ -330,7 +330,7 @@ export default function addLocaleRussian(locales) { "create-new-key": "Создать новый!", "duplicate-alias-error": "Найден дублирующийся псевдоним '{{alias}}'.
В рамках дашборда псевдонимы устройств должны быть уникальными.", "configure-alias": "Конфигурировать '{{alias}}' псевдоним", - "no-devices-matching": "Устройство '{{device}}' не найдено.", + "no-devices-matching": "Устройство '{{entity}}' не найдено.", "alias": "Псевдоним", "alias-required": "Псевдоним устройства обязателен.", "remove-alias": "Удалить псевдоним устройства", @@ -529,7 +529,7 @@ export default function addLocaleRussian(locales) { "system": "Системный", "select-plugin": "Выберите плагин", "plugin": "Плагин", - "no-plugins-matching": "Плагин '{{plugin}}' не найден.", + "no-plugins-matching": "Плагин '{{entity}}' не найден.", "plugin-required": "Плагин обязателен.", "plugin-require-match": "Пожалуйста, выберите существующий плагин.", "events": "События", diff --git a/ui/src/app/locale/locale.constant-zh.js b/ui/src/app/locale/locale.constant-zh.js index ba8e3c08da..32460702ec 100644 --- a/ui/src/app/locale/locale.constant-zh.js +++ b/ui/src/app/locale/locale.constant-zh.js @@ -235,7 +235,7 @@ export default function addLocaleChinese(locales) { "socialshare-text" : "'{{dashboardTitle}}' 由ThingsBoard提供支持", "socialshare-title" : "'{{dashboardTitle}}' 由ThingsBoard提供支持", "select-dashboard" : "选择仪表板", - "no-dashboards-matching" : "找不到符合 '{{dashboard}}' 的仪表板。", + "no-dashboards-matching" : "找不到符合 '{{entity}}' 的仪表板。", "dashboard-required" : "仪表板是必需的。", "select-existing" : "选择现有仪表板", "create-new" : "创建新的仪表板", @@ -330,7 +330,7 @@ export default function addLocaleChinese(locales) { "create-new-key": "创建一个新的!", "duplicate-alias-error" : "找到重复别名 '{{alias}}'。
设备别名必须是唯一的。", "configure-alias" : "配置 '{{alias}}' 别名", - "no-devices-matching" : "找不到与 '{{device}}' 匹配的设备。", + "no-devices-matching" : "找不到与 '{{entity}}' 匹配的设备。", "alias" : "别名", "alias-required" : "需要设备别名。", "remove-alias": "删除设备别名", @@ -529,7 +529,7 @@ export default function addLocaleChinese(locales) { "system" : "系统", "select-plugin" : "选择插件", "plugin" : "插件", - "no-plugins-matching" : "没有找到匹配'{{plugin}}'的插件。", + "no-plugins-matching" : "没有找到匹配'{{entity}}'的插件。", "plugin-required" : "插件是必需的。", "plugin-require-match" : "请选择一个现有的插件。", "events" : "事件", diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js index 50f6d8f5c7..d25db5da32 100644 --- a/ui/src/app/locale/locale.constant.js +++ b/ui/src/app/locale/locale.constant.js @@ -106,6 +106,12 @@ export default angular.module('thingsboard.locale', []) "enable-tls": "Enable TLS", "send-test-mail": "Send test mail" }, + "alarm": { + "alarm": "Alarm", + "select-alarm": "Select alarm", + "no-alarms-matching": "No alarms matching '{{entity}}' were found.", + "alarm-required": "Alarm is required" + }, "asset": { "asset": "Asset", "assets": "Assets", @@ -157,7 +163,10 @@ export default angular.module('thingsboard.locale', []) "unassign-assets-title": "Are you sure you want to unassign { count, select, 1 {1 asset} other {# assets} }?", "unassign-assets-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the customer.", "copyId": "Copy asset Id", - "idCopiedMessage": "Asset Id has been copied to clipboard" + "idCopiedMessage": "Asset Id has been copied to clipboard", + "select-asset": "Select asset", + "no-assets-matching": "No assets matching '{{entity}}' were found.", + "asset-required": "Asset is required" }, "attribute": { "attributes": "Attributes", @@ -169,6 +178,7 @@ export default angular.module('thingsboard.locale', []) "scope-shared": "Shared attributes", "add": "Add attribute", "key": "Key", + "last-update-time": "Last update time", "key-required": "Attribute key is required.", "value": "Value", "value-required": "Attribute value is required.", @@ -210,6 +220,7 @@ export default angular.module('thingsboard.locale', []) "enter-search": "Enter search" }, "customer": { + "customer": "Customer", "customers": "Customers", "management": "Customer management", "dashboard": "Customer Dashboard", @@ -246,7 +257,10 @@ export default angular.module('thingsboard.locale', []) "details": "Details", "events": "Events", "copyId": "Copy customer Id", - "idCopiedMessage": "Customer Id has been copied to clipboard" + "idCopiedMessage": "Customer Id has been copied to clipboard", + "select-customer": "Select customer", + "no-customers-matching": "No customers matching '{{entity}}' were found.", + "customer-required": "Customer is required" }, "datetime": { "date-from": "Date from", @@ -304,7 +318,7 @@ export default angular.module('thingsboard.locale', []) "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard", "select-dashboard": "Select dashboard", - "no-dashboards-matching": "No dashboards matching '{{dashboard}}' were found.", + "no-dashboards-matching": "No dashboards matching '{{entity}}' were found.", "dashboard-required": "Dashboard is required.", "select-existing": "Select existing dashboard", "create-new": "Create new dashboard", @@ -425,7 +439,7 @@ export default angular.module('thingsboard.locale', []) "create-new-key": "Create a new one!", "duplicate-alias-error": "Duplicate alias found '{{alias}}'.
Device aliases must be unique whithin the dashboard.", "configure-alias": "Configure '{{alias}}' alias", - "no-devices-matching": "No devices matching '{{device}}' were found.", + "no-devices-matching": "No devices matching '{{entity}}' were found.", "alias": "Alias", "alias-required": "Device alias is required.", "remove-alias": "Remove device alias", @@ -497,7 +511,8 @@ export default angular.module('thingsboard.locale', []) "unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", "is-gateway": "Is gateway", "public": "Public", - "device-public": "Device is public" + "device-public": "Device is public", + "select-device": "Select device" }, "dialog": { "close": "Close dialog" @@ -535,6 +550,9 @@ export default angular.module('thingsboard.locale', []) "type-plugin": "Plugin", "type-tenant": "Tenant", "type-customer": "Customer", + "type-user": "User", + "type-dashboard": "Dashboard", + "type-alarm": "Alarm", "select-entities": "Select entities", "no-aliases-found": "No aliases found.", "no-alias-matching": "'{{alias}}' not found.", @@ -672,7 +690,7 @@ export default angular.module('thingsboard.locale', []) "system": "System", "select-plugin": "Select plugin", "plugin": "Plugin", - "no-plugins-matching": "No plugins matching '{{plugin}}' were found.", + "no-plugins-matching": "No plugins matching '{{entity}}' were found.", "plugin-required": "Plugin is required.", "plugin-require-match": "Please select an existing plugin.", "events": "Events", @@ -685,6 +703,7 @@ export default angular.module('thingsboard.locale', []) "invalid-plugin-file-error": "Unable to import plugin: Invalid plugin data structure.", "copyId": "Copy plugin Id", "idCopiedMessage": "Plugin Id has been copied to clipboard" + }, "position": { "top": "Top", @@ -697,7 +716,24 @@ export default angular.module('thingsboard.locale', []) "change-password": "Change Password", "current-password": "Current password" }, + "relation": { + "relations": "Relations", + "entity-relations": "Entity relations", + "selected-relations": "{ count, select, 1 {1 relation} other {# relations} } selected", + "type": "Type", + "to-entity-type": "Entity type", + "to-entity-name": "Entity name", + "edit": "Edit relation", + "delete": "Delete relation", + "relation-type": "Relation type", + "relation-types": { + "Contains": "Contains", + "Manages": "Manages" + }, + "add": "Add relation" + }, "rule": { + "rule": "Rule", "rules": "Rules", "delete": "Delete rule", "activate": "Activate rule", @@ -749,12 +785,16 @@ export default angular.module('thingsboard.locale', []) "rule-file": "Rule file", "invalid-rule-file-error": "Unable to import rule: Invalid rule data structure.", "copyId": "Copy rule Id", - "idCopiedMessage": "Rule Id has been copied to clipboard" + "idCopiedMessage": "Rule Id has been copied to clipboard", + "select-rule": "Select rule", + "no-rules-matching": "No rules matching '{{entity}}' were found.", + "rule-required": "Rule is required" }, "rule-plugin": { "management": "Rules and plugins management" }, "tenant": { + "tenant": "Tenant", "tenants": "Tenants", "management": "Tenant management", "add": "Add Tenant", @@ -775,7 +815,10 @@ export default angular.module('thingsboard.locale', []) "details": "Details", "events": "Events", "copyId": "Copy tenant Id", - "idCopiedMessage": "Tenant Id has been copied to clipboard" + "idCopiedMessage": "Tenant Id has been copied to clipboard", + "select-tenant": "Select tenant", + "no-tenants-matching": "No tenants matching '{{entity}}' were found.", + "tenant-required": "Tenant is required" }, "timeinterval": { "seconds-interval": "{ seconds, select, 1 {1 second} other {# seconds} }", @@ -803,6 +846,7 @@ export default angular.module('thingsboard.locale', []) "time-period": "Time period" }, "user": { + "user": "User", "users": "Users", "customer-users": "Customer Users", "tenant-admins": "Tenant Admins", @@ -828,7 +872,10 @@ export default angular.module('thingsboard.locale', []) "last-name": "Last Name", "description": "Description", "default-dashboard": "Default dashboard", - "always-fullscreen": "Always fullscreen" + "always-fullscreen": "Always fullscreen", + "select-user": "Select user", + "no-users-matching": "No users matching '{{entity}}' were found.", + "user-required": "User is required" }, "value": { "type": "Value type", diff --git a/ui/src/scss/main.scss b/ui/src/scss/main.scss index 4ffabc975e..c062d4ea83 100644 --- a/ui/src/scss/main.scss +++ b/ui/src/scss/main.scss @@ -261,6 +261,45 @@ pre.tb-highlight { font-size: 16px; } +.tb-data-table { + md-toolbar { + z-index: 0; + } + span.no-data-found { + position: relative; + height: calc(100% - 57px); + text-transform: uppercase; + display: flex; + } + table.md-table { + tbody { + tr { + td { + &.tb-action-cell { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + min-width: 72px; + max-width: 72px; + width: 72px; + .md-button { + &.md-icon-button { + margin: 0; + padding: 6px; + width: 36px; + height: 36px; + } + } + .tb-spacer { + padding-left: 38px; + } + } + } + } + } + } +} + /*********************** * Flow